package org.apache.helix.tools;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

public class YAISCalculator {
  static class Assignment {
    private final int numNodes;
    private final int replication;
    Partition[] partitions;
    Node[] nodes;

    public Assignment(int numNodes, int numPartitions, int replication) {
      this.numNodes = numNodes;
      this.replication = replication;
      partitions = new Partition[numPartitions];
      for (int i = 0; i < numPartitions; i++) {
        partitions[i] = new Partition(i, replication);
      }
      nodes = new Node[numNodes];
      for (int i = 0; i < numNodes; i++) {
        nodes[i] = new Node(replication);
      }
    }

    public void assign(int partitionId, int replicaId, int nodeId) {
      System.out.println("Assigning (" + partitionId + "," + replicaId + ") to " + nodeId);
      partitions[partitionId].nodeIds[replicaId] = nodeId;
      nodes[nodeId].partitionLists.get(replicaId).push(partitionId);
    }

    public void unassign(int partitionId, int replicaId) {

    }

    Integer[] getPartitionsPerNode(int nodeId, int replicaId) {
      List<Integer> partitionsList = new ArrayList<Integer>();
      for (Partition p : partitions) {
        if (p.nodeIds[replicaId] == nodeId) {
          partitionsList.add(p.partionId);
        }
      }
      Integer[] array = new Integer[partitionsList.size()];
      partitionsList.toArray(array);
      return array;
    }

    public void printPerNode() {
      for (int nodeId = 0; nodeId < numNodes; nodeId++) {
        for (int r = 0; r < replication; r++) {
          StringBuilder sb = new StringBuilder();
          sb.append("(").append(nodeId).append(",").append(r).append("):\t");
          Node node = nodes[nodeId];
          LinkedList<Integer> linkedList = node.partitionLists.get(r);
          for (int partitionId : linkedList) {
            sb.append(partitionId).append(",");
          }
          System.out.println(sb.toString());
        }

      }
    }
  }

  static class Partition {

    final int partionId;

    public Partition(int partionId, int replication) {
      this.partionId = partionId;
      nodeIds = new int[replication];
      Arrays.fill(nodeIds, -1);
    }

    int nodeIds[];
  }

  static class Node {
    private final int replication;
    ArrayList<LinkedList<Integer>> partitionLists;

    public Node(int replication) {
      this.replication = replication;
      partitionLists = new ArrayList<LinkedList<Integer>>(replication);
      for (int i = 0; i < replication; i++) {
        partitionLists.add(new LinkedList<Integer>());
      }
    }

  }

  public static void main(String[] args) {
    doAssignment(new int[] {
      5
    }, 120, 3);
  }

  private static void doAssignment(int[] nodes, int partitions, int replication) {
    int N = nodes[0];
    int totalNodes = 0;
    for (int temp : nodes) {
      totalNodes += temp;
    }
    Assignment assignment = new Assignment(totalNodes, partitions, replication);
    int nodeId = 0;
    for (int i = 0; i < partitions; i++) {
      assignment.assign(i, 0, nodeId);
      nodeId = (nodeId + 1) % N;
    }
    Random random = new Random();
    for (int r = 1; r < replication; r++) {
      for (int id = 0; id < N; id++) {
        Integer[] partitionsPerNode = assignment.getPartitionsPerNode(id, 0);
        boolean[] used = new boolean[partitionsPerNode.length];
        Arrays.fill(used, false);
        System.out.println(id + "-" + partitionsPerNode.length);
        nodeId = (id + r) % N;
        int count = partitionsPerNode.length;
        boolean done = false;
        do {
          if (nodeId != id) {
            int nextInt = random.nextInt(count);
            int temp = 0;
            for (int b = 0; b < used.length; b++) {
              if (!used[b] && temp == nextInt) {
                assignment.assign(partitionsPerNode[b], r, nodeId);
                used[b] = true;
                break;
              }
            }
          }
          nodeId = (nodeId + 1) % N;
        } while (count > 0);

      }
    }
    if (nodes.length > 1) {
      int prevNodeCount = nodes[0];
      for (int i = 1; i < nodes.length; i++) {
        int newNodeCount = prevNodeCount + nodes[i];
        int masterPartitionsToMove =
            (int) ((partitions * 1.0 / prevNodeCount - partitions * 1.0 / newNodeCount) * 1 * prevNodeCount);
        while (masterPartitionsToMove > 0) {

        }

      }
    }
    assignment.printPerNode();
  }

}
