/*
 * P2Psum.java
 *
 * Created on May 2, 2005, 7:20 PM
 */

package DDMT.Nodes;

import java.util.*;
import java.io.*;
import jade.lang.acl.*;
import java.util.regex.*;
import DDMT.Agents.NodeAgent.AgentInterface;//not initial
import java.lang.Object;
import java.awt.geom.Point2D;
/**
 *
 * @author  kanishk1
 */
public class L2Peer extends NodeCode
{
    //Define patterns for integers, strings, doubles, first string, and last string
    private Pattern integerP = Pattern.compile("\\d+");
    private Pattern doubleP = Pattern.compile("\\d+\\p{Punct}\\d+");
    private Pattern stringP = Pattern.compile("\\S+\\s");
    private Pattern alphaStringP = Pattern.compile("[a-zA-Z]\\S*");
    private Pattern neighborP = Pattern.compile("\\s\\d+\\s\\d+\\p{Punct}\\d+");
    private Pattern fileP = Pattern.compile("\\S+\\s\\S+");
    private Pattern firstP = Pattern.compile("\\A\\S+");
    private Pattern lastP = Pattern.compile("\\S+\\Z");
    private Pattern middleP = Pattern.compile("\\s\\S+\\s");
    private Pattern relationP = Pattern.compile("\\A@[Rr][Ee][Ll][Aa][Tt][Ii][Oo][Nn]");
    private Pattern attributeTypeP = Pattern.compile("\\A@[Aa][Tt][Tt][Rr][Ii][Bb][Uu][Tt][Ee]\\s+\\S+\\s+\\S+");
    private Pattern attributeP = Pattern.compile("\\[S^,]*");
    private Pattern heteroDistP = Pattern.compile("\\s(\\S+)");
    private Matcher heteroDistM;
    private Matcher attributeM;
    private Matcher attributeTypeM;
    private Matcher relationM;
    private Matcher fileM;
    private Matcher firstM;
    private Matcher lastM;
    private Matcher middleM;
    private Matcher integerM;
    private Matcher doubleM;
    private Matcher stringM;
    private Matcher alphaStringM;
    private Matcher neighborM;

    //algorithm data structure
    int MAX_NEIGHBORS = 55;
    int NUM_CENTROIDS = 2;
    
    Vector S_it                 = new Vector();                         // original set of local points
    Vector DataTransferBuffer   = new Vector();
    Vector[] S_itc              = new Vector[NUM_CENTROIDS];                        // points initially labeled by K-means
    Vector CollectedData        = new Vector();
    Vector centroids            = new Vector();
    AvgVector[][] S_ijc         = new AvgVector[MAX_NEIGHBORS][NUM_CENTROIDS];      // i sends a message to j
    AvgVector[][] S_jic         = new AvgVector[MAX_NEIGHBORS][NUM_CENTROIDS];      // i receives a message from j
    AvgVector[] X_ic            = new AvgVector[NUM_CENTROIDS];                     // as defined in the notations
    AvgVector[] X_icnew         = new AvgVector[NUM_CENTROIDS];                  // as defined in the notations
    AvgVector[][] X_iandjc      = new AvgVector[MAX_NEIGHBORS][NUM_CENTROIDS];      // as defined in the notations
    AvgVector[][] X_inotjc      = new AvgVector[MAX_NEIGHBORS][NUM_CENTROIDS];      // as defined in the notations
    AvgVector[] S_itcavg        = new AvgVector[NUM_CENTROIDS];                     // avg of all local points

    Vector Perps = new Vector();
    Vector nbors = new Vector();
    Vector RefPoints = new Vector();
    boolean Change = false;
    String DataPath = "";
    int iteration = 0;
    int[] IterVector = new int[NUM_CENTROIDS];
    
    int[] Num_CtrlMessages = new int[this.NUM_CENTROIDS];
    int Num_DataMessages = 0;
    double ChangeInXiX = 0.0;
    double ChangeInXiY = 0.0;
    int[] flag = new int[this.MAX_NEIGHBORS];   //-1 implies null, 0 implies send and 1 means receive
    String MsgFile = "c:\\NoofMsg.txt";
    String CentroidFile = "c:\\CentroidList.txt";
    int TIME = 1;
    int IntervalofL2Msg = 500;
    int LastL2MsgSent = -500;

    String CorrectNessFile = "c:\\XiInstance.txt";

    int CorrectStatus = 0;
    DataGen dg ;
    Random r = new Random();
    int IntervalofDataAlert = 1000;
    int LastDataMsgAlert = 0;
    boolean AlertFlag = false;

    double epsilon = 2.0;
    double gamma = 1.1;
    double NoiseProb = 0.1;
    int SIZE_OF_DATABASE = 25;
    int NUM_NODES = 200;
    double PercentPointstoSend = 10;
    int dimension = 5;

    int d = 4*dimension;

    public L2Peer()
    {

    }

    public void start()
    {
        System.out.println("In start");
        //generate initial data for a peer
        //local data file is located at c:/Data/"NodeNum"/data"NodeNum".txt
        nbors = getNeighbors();
        DataPath = "C:\\L2Synthetic\\Data\\Node"+getNumber()+"\\";
        File f = new File(DataPath);

        f.mkdir();
        String S_itcPath = DataPath + "S_itc\\";
        f = new File(S_itcPath);
        if (!f.exists())
            f.mkdir();

        String X_icPath = DataPath + "X_ic\\";
        f = new File(X_icPath);
        if (!f.exists())
            f.mkdir();



        String X_inotjcPath = DataPath + "X_inotjc\\";
        f = new File(X_inotjcPath);
        if (!f.exists())
            f.mkdir();

        String X_iandjcPath = DataPath + "X_iandjc\\";
        f = new File(X_iandjcPath);
        if (!f.exists())
            f.mkdir();

        String LabelData = DataPath + "LabelData\\";
        f = new File(LabelData);
        if (!f.exists())
            f.mkdir();

        String InputDataFile = DataPath + "data.txt";


        //each node has different data
        dg = new DataGen(this.dimension);

        for (int i=0;i<this.SIZE_OF_DATABASE;i++)
        {
            dg.GenPoint(this.NUM_CENTROIDS, this.NoiseProb, 1);
            Point p = (Point)dg.GetPoint();
            this.S_it.add(p);
        }

        for (int i=0;i<this.SIZE_OF_DATABASE;i++)
        {
            dg.GenPoint(this.NUM_CENTROIDS, this.NoiseProb, 1);
            Point p = (Point)dg.GetPoint();
            this.DataTransferBuffer.add(p);
        }

        //set up the local ui's
        DistributeSpherePoints ds = new DistributeSpherePoints(this.d,this.dimension,200);
        Perps.addAll(ds.GetPoints());

        //generate the reference points
        //add the center of the circle (0,....,0)
        Point z = new Point(this.dimension);
        this.RefPoints.add(z);

        for (int i=0;i<this.Perps.size();i++)
        {
            Point x = (Point)this.Perps.elementAt(i);
            Point y = new Point(this.dimension);
            for (int j=0;j<y.d;j++)
                    y.x[j] = 2.0*this.epsilon*x.x[j];
            y.membership = -1;
            this.RefPoints.add(y);
        }

        //read the centroids from the file
        ArrayList Tempcentroids = ReadFile.read("E:\\Work\\Research\\L2Journal\\L2Synthetic\\ReferenceCentroids.txt");

        System.out.println(Tempcentroids.size());    
        for (int i=0;i<Tempcentroids.size();i++)
        {
            DataPoint dp = (DataPoint)Tempcentroids.get(i);
            double[] temp = new double[dp.DataArray.length];
            for (int j=0;j<dp.DataArray.length;j++)
                temp[j] = dp.DataArray[j];

            Point p = new Point(temp,i);
            centroids.add(p);
        }

        //DEBUG BEGINS
        //WriteFile(DataPath+"Mycentroids.txt", MakeString(centroids));
        //DEBUG ENDS

        for (int i=0;i<NUM_CENTROIDS;i++)
            S_itc[i] = new Vector();

        //label the local points based on the initial centroids
        System.out.println("Labeling Points of Site :"+getNumber());

      	Vector DummyVector = new Vector();
        for (int i=0;i<S_it.size();i++)
        {
            Point a = (Point)S_it.elementAt(i);
            Point newpt = new Point(a.d);
            for (int j=0;j<a.d;j++)
                newpt.x[j] = a.x[j];
            DummyVector.add(newpt);
        }

        for (int i=0;i<DummyVector.size();i++)
        {
            double RefDistance = Double.MAX_VALUE;
            int index = -1;
            Point a = (Point)DummyVector.elementAt(i);

            for (int j=0;j<centroids.size();j++)
            {
                Point b = (Point)centroids.elementAt(j);
                double distance = this.Distance(a,b);
                if (distance < RefDistance)
                {
                    RefDistance = distance;
                    index = j;
                }
            }

            Point b = (Point)centroids.elementAt(index);
            for (int j=0;j<b.d;j++)
		a.x[j] = a.x[j] - b.x[j];

            a.membership = index;
            S_itc[index].addElement(a);
        }

//        for (int i=0;i<NUM_CENTROIDS;i++)
//        {
//            String OutputDataFile = DataPath +"\\Labeldata\\"+ "Labeledata"+i+".txt";
//            WriteFile(OutputDataFile,MakeString(S_itc[i]));
//        }
        //        //DEBUG ENDS

        //initialization
        //set the flag to null for all the peers
        for (int i=0;i<this.nbors.size();i++)
        {
            this.flag[i] = -1;
        }

        for (int i=0;i<MAX_NEIGHBORS;i++)
        {
            for (int j=0;j<NUM_CENTROIDS;j++)
            {
                S_itcavg[j] = new AvgVector(this.dimension);
                X_ic[j] = new AvgVector(this.dimension);
                X_icnew[j] = new AvgVector(this.dimension);
                S_ijc[i][j] = new AvgVector(this.dimension);
                S_jic[i][j] = new AvgVector(this.dimension);
                X_iandjc[i][j] = new AvgVector(this.dimension);
                X_inotjc[i][j] = new AvgVector(this.dimension);
            }
        }

        //actual algorithm starts
        // for each centroid we do the following cumputation
        for (int i=0;i<centroids.size();i++)
        {
            //compute the avg vector S_itcavg[i]
            S_itcavg[i] = new AvgVector(S_itc[i],this.dimension);

            //DEBUG BEGIN
         //   WriteFile(DataPath+"S_itc\\"+"S_itcavg-"+i+".txt",MakeString(S_itcavg[i],0));
            //DEBUG END

            Point p = (Point)this.centroids.elementAt(i);
            AppendFile("c:\\Quality"+i+".txt", this.MakeString(this.S_itcavg[i]));
            //computing X_ic
            X_ic[i].size = S_itc[i].size();
            for( int k= 0; k<nbors.size(); k++)
                X_ic[i].size += S_jic[k][i].size;

			for (int j=0;j<this.dimension;j++)
            {
                X_ic[i].Avg.x[j] = S_itcavg[i].Avg.x[j]*S_itcavg[i].size;
               	for( int k= 0; k<nbors.size(); k++)
                    X_ic[i].Avg.x[j] += S_jic[k][i].Avg.x[j]*S_jic[k][i].size;

                if (X_ic[i].size!=0)
                    X_ic[i].Avg.x[j] /= X_ic[i].size;
                else
                    X_ic[i].Avg.x[j] = 0.0;
            }

            //DEBUG BEGIN
            File fp2 = new File(DataPath+"X_ic\\"+"X_ic-"+i+".txt");
            try
            {
                if (fp2.exists())
                {
                    fp2.delete();
                    fp2.createNewFile();
                }
                else
                    fp2.createNewFile();
            }
            catch (IOException e)
            {
                System.out.println(e.getStackTrace());
            }
      //      AppendFile(DataPath+"X_ic\\"+"X_ic-"+i+".txt",MakeString(X_ic[i],0));
            //DEBUG END

            //computing X_iandjc

            for( int k= 0; k<nbors.size(); k++)
                X_iandjc[k][i].size = S_ijc[k][i].size + S_jic[k][i].size;

            for (int j=0;j<this.dimension;j++)
            {
                for( int k= 0; k<nbors.size(); k++)
                {
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        if ( X_iandjc[k][i].size!=0)
                        {
                                X_iandjc[k][i].Avg.x[j] = (S_ijc[k][i].Avg.x[j] * S_ijc[k][i].size +
                                S_jic[k][i].Avg.x[j] * S_jic[k][i].size)/
                                (X_iandjc[k][i].size);
                        }
                        else
                                X_iandjc[k][i].Avg.x[j] = 0.0;
                }
            }


            //computing X_inotjc
            for( int k= 0; k<nbors.size(); k++)
                X_inotjc[k][i].size = X_ic[i].size - X_iandjc[k][i].size;

            for (int j=0;j<this.dimension;j++)
            {
                for( int k= 0; k<nbors.size(); k++)
                {
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        X_inotjc[k][i].Avg.x[j] = (X_ic[i].Avg.x[j] * X_ic[i].size -
                        X_iandjc[k][i].Avg.x[j] * X_iandjc[k][i].size)/
                        (X_inotjc[k][i].size);
                        //DEBUG BEGIN
                        //   WriteFile(DataPath+"X_inotjc\\"+"X_inotjc-"+n.getNumber()+i+".txt",MakeString(X_inotjc[k][i],0));
                        //DEBUG END
                }
            }
        }

       // this.AppendFile("c:\\X_ic.txt", ""+this.norm(this.X_ic[0])+"\n");

        String L2Msg = "";
        boolean SendL2 = false;
        //sending the message based on the two conditions

        for (int i=0;i<centroids.size();i++)
        {
            boolean SendMessage = false;
            int SendMessageTo = -1;
            double EdgeDelay = 0.0;

            Point p = this.FindNearestPoint(this.X_ic[i], RefPoints);
            for( int k= 0; k<nbors.size(); k++)
            {
                SendMessage = false;
                SendMessageTo = -1;
                int option = -1;

                //tie area
                if (!this.CheckInsideRegion(this.X_ic[i],p))
                {
                     if (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])
                         ||!this.CheckEqualSize(this.X_ic[i],this.X_iandjc[k][i]))
                     {
                        //flood the data
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        SendL2 = true;
                        option = 1;
                     }
                }

                if (option ==-1 && this.X_inotjc[k][i].size==0 &&
                    this.CheckInsideRegion(this.X_ic[i],p) &&
                    (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])))
                {
                    SendMessage = true;
                    Neighbor n = (Neighbor)nbors.elementAt(k);
                    SendMessageTo = n.getNumber();
                    EdgeDelay = n.getDelay();
                    SendL2 = true;
                    option = 2;
                }

                if (option ==-1 && this.CheckInsideRegion(this.X_ic[i],p)
                    && (!this.CheckInsideRegion(this.X_iandjc[k][i],p)
                    ||!this.CheckInsideRegion(this.X_inotjc[k][i],p)))
                {
                    //send something less
                    SendMessage = true;
                    Neighbor n = (Neighbor)nbors.elementAt(k);
                    SendMessageTo = n.getNumber();
                    EdgeDelay = n.getDelay();
                    SendL2 = true;
                    option = 3;
                }

                if (SendMessage)
                {
                    this.UpdateSij(k,i,this.PercentPointstoSend,option,p);
                    //Message String
                    L2Msg = L2Msg.concat(CreateMessage(S_ijc[k][i], S_ijc[k][i].size, i,k));

                    //Add the delay and the destination
                    L2Msg = L2Msg.concat("#"+SendMessageTo+"#"+(int)(EdgeDelay*1000.0)+"%");

                    this.UpdateAfterMsgSent(i,k);
                }
            }
//            if (SendToOne)
//                AppendFile(this.MsgFile, "0"+" "+i+" "+String.valueOf(Num_CtrlMessages[i])+"\n");
        }

       // this.AppendFile(this.XiFile, ""+this.TIME+" "+this.norm(this.X_ic[0])+"\n");
        //chenges for only L2
        if (this.norm(this.X_ic[0])>this.epsilon)
            CorrectStatus = 1;
        else
            CorrectStatus = 0;


        this.AppendFile(this.CorrectNessFile, ""+this.TIME+" "+this.CorrectStatus+"\n");

        boolean SendDataSet = false;
        String DataSet = "";
        String DataMsg = "";

        //now sent the data if necessary
        boolean SendWaitDataMsg = false;

        for (int i=0;i<centroids.size();i++)
        {
            if (this.norm(this.X_ic[i])>=this.epsilon)
            {
                //bad luck....send the data
                //if this is a leaf node
                if (this.nbors.size()==1)
                {
                    SendDataSet = true;
                    DataSet = CreateDataSet();
                }
            }
        }

        int index = -1;

        if(SendDataSet)
        {
            for (int i=0;i<this.nbors.size();i++)
            {
                Neighbor n = (Neighbor)nbors.elementAt(i);
                if (this.flag[i]==-1)
                {
                    index = i;
                    DataMsg = DataMsg.concat(DataSet+"#"+n.getNumber()+"#"+(int)(n.getDelay()*1000.0)+"%");
                    this.Num_DataMessages=1;
                    if (!this.AlertFlag)
                    {
                        this.AlertFlag = true;
                        this.LastDataMsgAlert = this.TIME;
                    }
                }
                else
                    SendDataSet = false;
            }
        }

        if (DataMsg.equals(""))
            this.AlertFlag = false;

        //now sent the msg depending on the conditions
        String Msg = "Initialization Msg!";

        //no meesage needs to be sent
        if (L2Msg.equals("")&&DataMsg.equals(""))
            Msg = "Empty Initialization Msg!";

        //check for L2 msg
        if (!L2Msg.equals(""))
        {
            //check the time
            if (this.TIME>=this.LastL2MsgSent+this.IntervalofL2Msg)
            {
                Msg = Msg.concat(L2Msg);
                this.LastL2MsgSent = this.TIME;

            }
            else
            {
                int waitTime = this.IntervalofL2Msg + this.LastL2MsgSent - this.TIME;
                Msg = Msg.concat("Wait Msg#"+this.getNumber()+"#"+waitTime+"%");
            }
        }


        if (this.AlertFlag)
        {
            if (this.TIME>=this.LastDataMsgAlert+this.IntervalofDataAlert)
            {
                Msg = Msg.concat(DataMsg);
                //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data sent by "+this.getNumber()+"\n");
                this.flag[index]=0;         // change to send
                this.AlertFlag = false;     //reset alert flag
            }
            else
            {
		int waitTime = this.IntervalofDataAlert + this.LastDataMsgAlert - this.TIME;
                Msg = Msg.concat("Wait Data Msg#"+this.getNumber()+"#"+waitTime+"%");
                //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Wake Up Data Sent by "+this.getNumber()+"\n");
            }
        }

        iface.sendMessage(Msg,this.getNumber());
    }

    public void run(String m, int num)
    {
        int factor = 100000;
        //stop simulation
        if (this.TIME>20*factor)
        {
            Expt_Script ex = new Expt_Script();

            try
            {
                ex.NormCalc(this.NUM_NODES,this.dimension);
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            ex.PoBoxMessages();
            ex.AverageSi(this.NUM_NODES);
            System.exit(0);
        }


   //     System.out.println(m);
        if (m.startsWith("Wait Msg"))
        {
        //    System.out.println("Waiting L2");
            String[] result = m.split("\n");
            this.TIME = Integer.parseInt(result[result.length-1]);
            this.WakeUp();
        }
        else
            if (m.startsWith("Wait Data Msg"))
            {
                String[] result = m.split("\n");
            //    System.out.println("Waiting Data "+this.getNumber());
                this.TIME = Integer.parseInt(result[result.length-1]);
            //    this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Wake Up Data Recvd by "+this.getNumber()+"\n");
                this.WakeUpForData();
            }
        else
        if (m.startsWith("DataGen"))
        {
        //    System.out.println("Msg recvd from : "+num +" by "+getNumber()+" for new data generation");
        //    System.out.println(m);
            //extract the time of the message

	    StringTokenizer st = new StringTokenizer(m,"\n");
            String Temp = st.nextToken();
            String[] Temp2 = Temp.split(" ");
            String numPointstoAdd = Temp2[Temp2.length-1];
            Temp = st.nextToken();
            String Time = st.nextToken();

            this.TIME = Integer.parseInt(Time);
            this.AddPoint(Integer.parseInt(numPointstoAdd));
        }
        else
            if (m.startsWith("Centroid"))
            {
            //    System.out.println(m);
                String[] result = m.split("\n");
                System.out.println("Centroid recvd from "+result[result.length-2]+" by "+this.getNumber());
                Neighbor n = null;

                this.centroids = new Vector();
                FetchCentroids(m);
                this.CollectedData = new Vector();

                String CentroidString = MakeCentroidString();
                String Msg = "";


                for (int i=0;i<this.nbors.size();i++)
                {
                    // for all the received members
                    if (this.flag[i]==1)
                    {
                        n = (Neighbor)nbors.elementAt(i);
                        Msg = Msg.concat(CentroidString+"#"+n.getNumber()+"#"+(int)(n.getDelay()*1000.0)+"%");
                        this.Num_DataMessages=1;
//                        AppendFile(this.MsgFile, this.TIME+" "+String.valueOf(Num_DataMessages)+"\n");

                    }
                    this.flag[i] = -1;
                }
                RunLocalL2(Msg);
            }
            else if (m.startsWith("DataSet"))
            {
                int index = -1;
                Neighbor n = null;
                String[] result = m.split("\n");
                for (int i=0;i<nbors.size();i++)
                {
                    n = (Neighbor)nbors.elementAt(i);
                    if (n.getNumber()==Integer.parseInt(result[result.length-2]))
                    {
                        index = i;
                        break;
                    }
                }

                System.out.println("DataSet recvd from "+Integer.parseInt(result[result.length-2]) +" by "+this.getNumber());

                GetTime(m);

                //this.AppendFile("c:\\WakeUpData.txt", "Time : "+this.TIME+ " DataSet recvd from "+Integer.parseInt(result[result.length-2]) +" by "+this.getNumber()+"\n");
                if (index!=-1)
                {
                    // if not already received
                    if (flag[index]!=1)
                        AccumulateRemoteData(m);
                }

                //set the flag to received
                this.flag[index] = 1;

                int NumRecvd=0;
                for (int i=0;i<this.nbors.size();i++)
                {
                    if (this.flag[i] == 1)
                    {
                        NumRecvd++;
                    }
                }

                String DataMsg = "";
                index = -1;
                //the data will be propageted if the peer has received data from all the peers except one
                if (NumRecvd == nbors.size()-1)
                {
                    //the message may need to be propageted
                    String DataSet = "";

                    boolean ToSent = false;
                    for (int i=0;i<this.NUM_CENTROIDS;i++)
                        if (this.norm(this.X_ic[i])>epsilon)
                        {
                            ToSent = true;
                            DataSet = this.CreateDataSet();
                            break;
                        }

                    if (ToSent)
                    {
                        //send the collectedData now
                        for (int i=0;i<this.nbors.size();i++)
                        {
                            if (flag[i]==-1)
                            {
                                n = (Neighbor)nbors.elementAt(i);
                                DataMsg = DataMsg.concat(DataSet+"#"+n.getNumber()+"#"+(int)(n.getDelay()*1000.0)+"%");
                                index = i;
                                this.Num_DataMessages=1;
//                                AppendFile(this.MsgFile, this.TIME+" "+String.valueOf(Num_DataMessages)+"\n");
                                if (!this.AlertFlag)
                                {
                                    this.AlertFlag = true;
                                    this.LastDataMsgAlert = this.TIME;
                                }
                            }
                        }
                    }

                    if (DataMsg.equals(""))
                    	this.AlertFlag = false;

		    String Msg = "";
                    if (this.AlertFlag)
                    {
                    	if (this.TIME>=this.LastDataMsgAlert+this.IntervalofDataAlert)
                    	{
                            Msg = Msg.concat(DataMsg);
                            //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data sent by "+this.getNumber()+"\n");
                            this.flag[index] = 0;
                            this.AlertFlag = false;     //reset alert flag
                    	}
            	    	else
			{
                            int waitTime = this.LastDataMsgAlert + this.IntervalofDataAlert - this.TIME;
                            Msg = Msg.concat("Wait Data Msg#"+this.getNumber()+"#"+waitTime+"%");
                            //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Wake Up Data Sent by "+this.getNumber()+"\n");
                        }
                    }

                    if (Msg.equals(""))
                        Msg = "Empty Msg";

                    iface.sendMessage(Msg, this.getNumber());

                }
                else
                    if (NumRecvd == this.nbors.size())
                    {
                        //this is a root Node and it has to do a local k-means on the entire DataSet
                        // first add the local data S_it to the CollectedData base

                        this.CollectedData.addAll(this.S_it);
                        if (this.CollectedData.size()!=this.SIZE_OF_DATABASE*(this.NUM_NODES))
                        {
                            System.out.println("Size of DataSet is not proper");
                            System.exit(0);
                        }

                        Kmeans km = new Kmeans(this.NUM_CENTROIDS,this.CollectedData,0.5,this.TIME,this.dimension);
                        this.centroids = km.ReturnCentroids();
                        System.out.println("Execution Complete");
                        String CentroidString = MakeCentroidString();

                        this.AppendFile("c:\\K-meansTime.txt", ""+this.TIME+"\n");
                        this.AppendFile("c:\\K-meansTime.txt", CentroidString+"\n\n");
//                        this.AppendFile("c:\\DataSet.txt", this.TIME+"\n"+this.MakeString(this.CollectedData)+"\n\n");
//                        this.AppendFile("c:\\DataSet.txt", this.MakeString(this.centroids)+"\n\n");
//

                        for (int i=0;i<this.nbors.size();i++)
                        {
                            n = (Neighbor)nbors.elementAt(i);
                            DataMsg = DataMsg.concat(CentroidString+"#"+n.getNumber()+"#"+(int)(n.getDelay()*1000.0)+"%");
                            this.flag[i] = -1;
                            this.Num_DataMessages=1;
//                            AppendFile(this.MsgFile, this.TIME+" "+String.valueOf(Num_DataMessages)+"\n");
                            System.out.println("Send centroids to "+n.getNumber());
                        }
                        this.CollectedData = new Vector();
                        this.RunLocalL2(DataMsg);
                    }
                    else
                    {
                        if (DataMsg.equals(""))
                        {
                            DataMsg = "Empty Msg";
                            iface.sendMessage(DataMsg, this.getNumber());
                        }
                    }

                //for L2
//                String Msg ="";
//                if (Msg.equals(""))
//                {
//                    Msg = "Empty Msg";
//                    iface.sendMessage(Msg, this.getNumber());
//                }
            }
            else
            {
                String[] result1 = m.split("\n");

            //    this.AppendFile("c:\\MsgDebug.txt","Msg recvd from : "+result1[result1.length-2] +" by "+getNumber()+"\n\n");

                String temp = FetchMessageComponents(m);
                String[] result = temp.split(" ");
                int i = Integer.parseInt(result[0]);
                this.TIME = Integer.parseInt(result[1]);

              //  System.out.println(this.TIME);
              //  System.out.println("Msg recvd from : "+result1[result1.length-2] +" by "+getNumber() +" for centroid no "+i);
                boolean SendMessage = false;
                int SendMessageTo = -1;
                double EdgeDelay = 0.0;

                //recompute the sufficient statistics
                //computing X_ic
                boolean ToChange = false;
                X_icnew[i].size = S_itc[i].size();
                for( int k= 0; k<nbors.size(); k++)
                    X_icnew[i].size += S_jic[k][i].size;

                for (int j=0;j<this.dimension;j++)
                {
                    X_icnew[i].Avg.x[j] = S_itcavg[i].Avg.x[j]*S_itcavg[i].size;
                    for( int k= 0; k<nbors.size(); k++)
                            X_icnew[i].Avg.x[j] += S_jic[k][i].Avg.x[j]*S_jic[k][i].size;
                    if (X_icnew[i].size!=0)
                            X_icnew[i].Avg.x[j] /= X_icnew[i].size;
                    else
                            X_icnew[i].Avg.x[j] = 0.0;

                }



                //DEBUG BEGIN
          //      AppendFile(DataPath+"X_ic\\"+"X_ic-"+i+".txt",MakeString(X_icnew[i],0));
                //DEBUG END

                for (int j=0;j<this.dimension;j++)
                {
                    if(X_icnew[i].Avg.x[j] != X_ic[i].Avg.x[j])
                    {
                            ToChange = true;
                            break;
                    }
                }

                for (int j=0;j<this.dimension;j++)
                    X_ic[i].Avg.x[j] = X_icnew[i].Avg.x[j];
                X_ic[i].size =  X_icnew[i].size;

            //    this.AppendFile("c:\\MsgDebug.txt", ""+this.MakeString(this.X_ic[0],0)+"\n\n");

                //computing X_iandjc

                for( int k= 0; k<nbors.size(); k++)
                    X_iandjc[k][i].size = S_ijc[k][i].size + S_jic[k][i].size;

                for (int j=0;j<this.dimension;j++)
                {
                    for( int k= 0; k<nbors.size(); k++)
                    {
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        if ( X_iandjc[k][i].size!=0)
                        {
                                X_iandjc[k][i].Avg.x[j] = (S_ijc[k][i].Avg.x[j] * S_ijc[k][i].size +
                                S_jic[k][i].Avg.x[j] * S_jic[k][i].size)/
                                (X_iandjc[k][i].size);
                        }
                        else
                                X_iandjc[k][i].Avg.x[j] = 0.0;
                        //   AppendFile(DataPath+"X_iandjc\\"+"X_iandjc-"+n.getNumber()+i+".txt",MakeString(X_iandjc[k][i],0));
                    }
                }

                //Xinotj
                for (int j=0;j<this.dimension;j++)
                {
                    for( int k= 0; k<nbors.size(); k++)
                    {
                        X_inotjc[k][i].size = X_ic[i].size - X_iandjc[k][i].size;
                    }

                    for( int k= 0; k<nbors.size(); k++)
                    {
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        if (X_inotjc[k][i].size!=0)
                        {
                            X_inotjc[k][i].Avg.x[j] = (X_ic[i].Avg.x[j] * X_ic[i].size -
                            X_iandjc[k][i].Avg.x[j] * X_iandjc[k][i].size)/
                            (X_inotjc[k][i].size);
                        }
                        else
                                X_inotjc[k][i].Avg.x[j] = 0.0;
                        //DEBUG BEGIN
                        //DEBUG END
                    }
                }


                String L2Msg = "";

                //conditions for sending a message
                int option = -1;
                boolean SendToOne = false;

                Point p = this.FindNearestPoint(this.X_ic[i], RefPoints);
                for( int k= 0; k<nbors.size(); k++)
                {
                    SendMessage = false;
                    SendMessageTo = -1;
                    option = -1;

                    if (!this.CheckInsideRegion(this.X_ic[i],p))
                    {
                         if (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])
                             ||!this.CheckEqualSize(this.X_ic[i],this.X_iandjc[k][i]))
                         {
                            //flood the data
                            SendMessage = true;
                            Neighbor n = (Neighbor)nbors.elementAt(k);
                            SendMessageTo = n.getNumber();
                            EdgeDelay = n.getDelay();
                            option = 1;
                         }
                    }

                    if (option ==-1 && this.X_inotjc[k][i].size==0 &&
                        this.CheckInsideRegion(this.X_ic[i],p) &&
                       (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])))
                    {
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        option = 2;
                    }
                    //not a tie...Ki lies in a convex region
                    if (option ==-1 &&
                        this.CheckInsideRegion(this.X_ic[i],p)
                        && (!this.CheckInsideRegion(this.X_iandjc[k][i],p)
                        ||!this.CheckInsideRegion(this.X_inotjc[k][i],p)))
                    {
                        //send something less
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        option = 3;
                    }


                    if (SendMessage)
                    {
                        if (this.TIME>=this.LastL2MsgSent+this.IntervalofL2Msg)
							this.UpdateSij(k,i,this.PercentPointstoSend,option,p);


                        L2Msg = L2Msg.concat(CreateMessage(S_ijc[k][i], S_ijc[k][i].size, i,k));
                        L2Msg = L2Msg.concat("#"+SendMessageTo+"#"+(int)(EdgeDelay*1000.0)+"%");
                        SendToOne = true;
                        Num_CtrlMessages[i]++;

                        if (this.TIME>=this.LastL2MsgSent+this.IntervalofL2Msg)
                        {
                            this.UpdateAfterMsgSent(i,k);
                        }
                    }
                }


                int NumRecvd=0;
                for (int j=0;j<this.nbors.size();j++)
                {
                    if (this.flag[j] == 1)
                    {
                        NumRecvd++;
                    }
                }

               // this.AppendFile(this.XiFile, ""+this.TIME+" "+this.norm(this.X_ic[0])+"\n");

                int savedStatus = this.CorrectStatus;

                if (this.norm(this.X_ic[0])>this.epsilon)
                    this.CorrectStatus = 1;
                else
                    this.CorrectStatus = 0;

                if (this.CorrectStatus!=savedStatus)
                    this.AppendFile(this.CorrectNessFile, ""+this.TIME+" "+this.CorrectStatus+"\n");

              //  this.AppendFile(XiFile, ""+this.TIME+" "+this.norm(this.X_ic[0])+"\n");

                String DataSet = "";
                boolean ToSend = false;
                if (NumRecvd == this.nbors.size()-1)
                {
                    for (int k=0;k<centroids.size();k++)
                    {
                        if (this.norm(this.X_ic[k])>=this.epsilon)
                        {
                            ToSend = true;
                            DataSet = CreateDataSet();
                            break;
                        }
                    }
                }
                int index = -1;
                String DataMsg = "";
                boolean DataSetToSend = false;
                if (ToSend)
                {
                    for (int j=0;j<this.nbors.size();j++)
                    {
                        if (this.flag[j]==-1)
                        {
                            Neighbor n = (Neighbor)nbors.elementAt(j);

                            index = j;
                            DataMsg = DataMsg.concat(DataSet+"#"+n.getNumber()+"#"+(int)(n.getDelay()*1000.0)+"%");
                            this.Num_DataMessages=1;
//                            AppendFile(this.MsgFile, this.TIME+" "+String.valueOf(Num_DataMessages)+"\n");
                            DataSetToSend = true;
                            if (!this.AlertFlag)
                            {
                                this.AlertFlag = true;
                                this.LastDataMsgAlert = this.TIME;
                            }
                            //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data needs to be sent by "+this.getNumber()+"\n");
                        }
                    }
                }

                if (DataMsg.equals(""))
                    this.AlertFlag = false;

                //now sent the msg depending on the conditions
                String Msg = "";

                //no meesage needs to be sent
                if (L2Msg.equals("")&&DataMsg.equals(""))
                    Msg = "Empty Msg";

                //check for L2 msg
                if (!L2Msg.equals(""))
                {
                    //check the time
                    if (this.TIME>=this.LastL2MsgSent+this.IntervalofL2Msg)
                    {
                        Msg = Msg.concat(L2Msg);
                        this.LastL2MsgSent = this.TIME;

                    }
                    else
                    {
                        int waitTime = this.IntervalofL2Msg + this.LastL2MsgSent - this.TIME;
                        Msg = Msg.concat("Wait Msg#"+this.getNumber()+"#"+waitTime+"%");

                    }
                }

                //Data Msg
                if (this.AlertFlag)
                {
                    if (this.TIME>=this.LastDataMsgAlert+this.IntervalofDataAlert)
                    {
                        Msg = Msg.concat(DataMsg);
                        //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data sent by "+this.getNumber()+"\n");
                        this.flag[index]=0;         // change to send
                        this.AlertFlag = false;     //reset alert flag
                    }
                    else
                    {
                        int waitTime = this.LastDataMsgAlert + this.IntervalofDataAlert - this.TIME;
                        Msg = Msg.concat("Wait Data Msg#"+this.getNumber()+"#"+waitTime+"%");
                        //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Wake Up Data Sent by "+this.getNumber()+"\n");
                    }
                }

                iface.sendMessage(Msg,this.getNumber());
            }
    }

    public void WakeUpForData()
    {
        String Msg = "";
        String DataMsg = "";
        if (this.AlertFlag)
        {
            String DataSet = CreateDataSet();
            int index = -1;
            for (int j=0;j<this.nbors.size();j++)
            {
                if (this.flag[j]==-1)
                {
                    Neighbor n = (Neighbor)nbors.elementAt(j);
                    index = j;
                    DataMsg = DataMsg.concat(DataSet+"#"+n.getNumber()+"#"+(int)(n.getDelay()*1000.0)+"%");
                    this.Num_DataMessages=1;
                    //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data needs to be sent by "+this.getNumber()+"\n");
                }
            }

            if (this.TIME>=this.LastDataMsgAlert+this.IntervalofDataAlert)
            {
                Msg = Msg.concat(DataMsg);
                //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data sent by "+this.getNumber()+"\n");
                this.flag[index]=0;         // change to send
                this.AlertFlag = false;     //reset alert flag
            }
            else
            {
                int waitTime = this.LastDataMsgAlert + this.IntervalofDataAlert - this.TIME;
                Msg = Msg.concat("Wait Data Msg#"+this.getNumber()+"#"+waitTime+"%");
                //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Wake Up Data Sent by "+this.getNumber()+"\n");
            }

            iface.sendMessage(Msg, this.getNumber());

        }
        else
        {
            Msg = "Empty Msg";
            iface.sendMessage(Msg, this.getNumber());
        }
    }

    public void WakeUp()
    {
        String L2Msg = "";

        for (int i=0;i<centroids.size();i++)
        {
            //conditions for sending a message
            int option = 0;
            boolean SendToOne = false;
            boolean SendMessage = false;
            int SendMessageTo = -1;
            double EdgeDelay = 0.0;
            Point p = this.FindNearestPoint(this.X_ic[i], RefPoints);
            for( int k= 0; k<nbors.size(); k++)
            {
                SendMessage = false;
                SendMessageTo = -1;
                option = -1;

                if (!this.CheckInsideRegion(this.X_ic[i],p))
                {
                     if (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])
                         ||!this.CheckEqualSize(this.X_ic[i],this.X_iandjc[k][i]))
                     {
                        //flood the data
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        option = 1;
                     }
                }

                if (option ==-1 &&
                   this.CheckInsideRegion(this.X_ic[i],p)  &&
                   this.X_inotjc[k][i].size==0 &&
                   (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])))
                    {
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        option = 2;
                    }
                //not a tie...Ki lies in a convex region
                if (option ==-1 &&
                    this.CheckInsideRegion(this.X_ic[i],p) &&
                    (!this.CheckInsideRegion(this.X_iandjc[k][i],p)
                    ||!this.CheckInsideRegion(this.X_inotjc[k][i],p)))
                    {
                        //send something less
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        option = 3;
                    }

                if (SendMessage)
                {
//                    this.PrintMsgStatsBefore(k, SendMessageTo, option, p);
                    this.UpdateSij(k,i,this.PercentPointstoSend,option,p);

                    L2Msg = L2Msg.concat(CreateMessage(S_ijc[k][i], S_ijc[k][i].size, i,k));
                    L2Msg = L2Msg.concat("#"+SendMessageTo+"#"+(int)(EdgeDelay*1000.0)+"%");

                    SendToOne = true;
                    this.UpdateAfterMsgSent(i,k);
                }
            }
         }



        //now sent the data if necessary (a heavy communication indeed)
        //first check if sending the data is allowed
        int NumRecvd=0;
        for (int j=0;j<this.nbors.size();j++)
        {
            if (this.flag[j] == 1)
            {
                NumRecvd++;
            }
        }

     //   this.AppendFile(this.XiFile, ""+this.TIME+" "+this.norm(this.X_ic[0])+"\n");
        int savedStatus = this.CorrectStatus;

        if (this.norm(this.X_ic[0])>this.epsilon)
            this.CorrectStatus = 1;
        else
            this.CorrectStatus = 0;

        if (this.CorrectStatus!=savedStatus)
            this.AppendFile(this.CorrectNessFile, ""+this.TIME+" "+this.CorrectStatus+"\n");

      //  this.AppendFile(XiFile, ""+this.TIME+" "+this.norm(this.X_ic[0])+"\n");
        String DataSet = "";
        String DataMsg = "";
        int index = -1;
        boolean ToSend = false;
        if (NumRecvd == this.nbors.size()-1)
        {
            for (int i=0;i<centroids.size();i++)
            {
                if (this.norm(this.X_ic[i])>=this.epsilon)
                {
                    ToSend = true;
                    DataSet = CreateDataSet();
                    break;
                }
            }
        }

        if (ToSend)
        {
            for (int j=0;j<this.nbors.size();j++)
            {
                if (this.flag[j]==-1)
                {
                    Neighbor n = (Neighbor)nbors.elementAt(j);
                    index = j;
                    DataMsg = DataMsg.concat(DataSet+"#"+n.getNumber()+"#"+(int)(n.getDelay()*1000.0)+"%");
                    //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data needs to be sent by "+this.getNumber()+"\n");
                    this.Num_DataMessages=1;
                    if (!this.AlertFlag)
                    {
                        this.AlertFlag = true;
                        this.LastDataMsgAlert = this.TIME;
                    }
                }
            }
        }

        if (DataMsg.equals(""))
            this.AlertFlag = false;

        //now sent the msg depending on the conditions
        String Msg = "";

        //no meesage needs to be sent
        if (L2Msg.equals("")&&DataMsg.equals(""))
            Msg = "Empty Msg";

        //check for L2 msg
        if (!L2Msg.equals(""))
        {
            //check the time
            if (this.TIME>=this.LastL2MsgSent+this.IntervalofL2Msg)
            {
                Msg = Msg.concat(L2Msg);
                this.LastL2MsgSent = this.TIME;
            }
            else
            {
                int waitTime = this.IntervalofL2Msg + this.LastL2MsgSent - this.TIME;
                Msg = Msg.concat("Wait Msg#"+this.getNumber()+"#"+waitTime+"%");
            }

        }

        //check for Data msg
        if (this.AlertFlag)
        {
            if (this.TIME>=this.LastDataMsgAlert+this.IntervalofDataAlert)
            {
                Msg = Msg.concat(DataMsg);
                //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data sent by "+this.getNumber()+"\n");
                this.flag[index]=0;         // change to send
                this.AlertFlag = false;     //reset alert flag
            }
            else
            {
                int waitTime = this.LastDataMsgAlert + this.IntervalofDataAlert - this.TIME;
                Msg = Msg.concat("Wait Data Msg#"+this.getNumber()+"#"+waitTime+"%");
                //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Wake Up Data Sent by "+this.getNumber()+"\n");
            }
        }

        iface.sendMessage(Msg,this.getNumber());
    }

    public void RunLocalL2(String PassedMsg)
    {
        boolean DataSetToSend = false;
        String L2Msg = "";

        String PassedCentroids = "";
        if (PassedMsg!="")
        {
            DataSetToSend = true;
            PassedCentroids = PassedMsg;
        }

    //    System.out.println("In Local L2 for "+this.getNumber());
        //remove the old points first
        for (int i=0;i<this.centroids.size();i++)
        {
            this.S_itc[i].removeAllElements();
            Point b = (Point)this.centroids.elementAt(i);
        //    System.out.println(b.x+" "+b.y);
        }

        Vector DummyVector = new Vector();
        for (int i=0;i<S_it.size();i++)
        {
            Point a = (Point)S_it.elementAt(i);
           	Point newpt = new Point(this.dimension);
		    for (int j=0;j<this.dimension;j++)
		    	newpt.x[j] = a.x[j];
            DummyVector.add(newpt);
        }

        //relabel the points
        for (int i=0;i<DummyVector.size();i++)
        {
            double RefDistance = Double.MAX_VALUE;
            int index = -1;
            Point a = (Point)DummyVector.elementAt(i);
            for (int j=0;j<this.centroids.size();j++)
            {
                Point b = (Point)this.centroids.elementAt(j);
                double distance = this.Distance(a,b);
                if (distance < RefDistance)
                {
                    RefDistance = distance;
                    index = j;
                }
            }
            Point b = (Point)this.centroids.elementAt(index);
            for (int j=0;j<this.dimension;j++)
            	a.x[j] = a.x[j] - b.x[j];
            a.membership = index;
            S_itc[index].add(a);
        }

        //actual algorithm starts
        // for each centroid we do the following cumputation

//        for (int i=0;i<centroids.size();i++)
//        {
//            for( int k= 0; k<nbors.size(); k++)
//            {
//                this.S_ijc[k][i].Avg.x = 0.0;
//                this.S_ijc[k][i].Avg.y = 0.0;
//
//                this.S_jic[k][i].Avg.x = 0.0;
//                this.S_jic[k][i].Avg.y = 0.0;
//
//                this.S_ijc[k][i].size = 0;
//                this.S_jic[k][i].size = 0;
//            }
//
//        }

        for (int i=0;i<centroids.size();i++)
        {

            double[] oldSi = new double[this.dimension];
            double[] newSi = new double[this.dimension];
            int oldSisize = 0;
            int newSisize = 0;
            oldSisize = this.S_itcavg[i].size;
            for (int j=0;j<this.dimension;j++)
                    oldSi[j] = this.S_itcavg[i].Avg.x[j];

            S_itcavg[i] = new AvgVector(S_itc[i],this.dimension);
            newSisize = this.S_itcavg[i].size;
            for (int j=0;j<this.dimension;j++)
                    newSi[j] = this.S_itcavg[i].Avg.x[j];


            for (int j=0;j<this.dimension;j++)
            {
                //computing X_ic
                X_ic[i].size = S_itc[i].size();
                for( int k= 0; k<nbors.size(); k++)
                        X_ic[i].size += S_jic[k][i].size;

                X_ic[i].Avg.x[j] = S_itcavg[i].Avg.x[j]*S_itcavg[i].size;
                for( int k= 0; k<nbors.size(); k++)
                        X_ic[i].Avg.x[j] += S_jic[k][i].Avg.x[j]*S_jic[k][i].size;

                if (X_ic[i].size!=0)
                        X_ic[i].Avg.x[j] /= X_ic[i].size;
                else
                        X_ic[i].Avg.x[j] = 0.0;

                AppendFile(DataPath+"X_ic\\"+"X_ic-"+i+".txt",MakeString(X_ic[i]));
                //DEBUG END

                //computing X_iandjc

                for( int k= 0; k<nbors.size(); k++)
                        X_iandjc[k][i].size = S_ijc[k][i].size + S_jic[k][i].size;

                for( int k= 0; k<nbors.size(); k++)
                {
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        if ( X_iandjc[k][i].size!=0)
                        {
                                X_iandjc[k][i].Avg.x[j] = (S_ijc[k][i].Avg.x[j] * S_ijc[k][i].size +
                                S_jic[k][i].Avg.x[j] * S_jic[k][i].size)/
                                (X_iandjc[k][i].size);
                        }
                        else
                                X_iandjc[k][i].Avg.x[j] = 0.0;

                }

                //computing X_inotjc
                for( int k= 0; k<nbors.size(); k++)
                        X_inotjc[k][i].size = X_ic[i].size - X_iandjc[k][i].size;

                for( int k= 0; k<nbors.size(); k++)
                {
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        if (X_inotjc[k][i].size!=0)
                        {
                                X_inotjc[k][i].Avg.x[j] = (X_ic[i].Avg.x[j] * X_ic[i].size -
                                X_iandjc[k][i].Avg.x[j] * X_iandjc[k][i].size)/
                                (X_inotjc[k][i].size);
                        }
                        else
                                X_inotjc[k][i].Avg.x[j] = 0.0;
                }
            }
            this.AppendFile("c:\\Quality"+i+".txt",""+this.TIME+" ");
            for (int j=0;j<this.dimension;j++)
                this.AppendFile("c:\\Quality"+i+".txt",String.valueOf(newSi[j]-oldSi[j])+" ");
            this.AppendFile("c:\\Quality"+i+".txt",String.valueOf(newSisize-oldSisize)+"\n");
        }

         for (int i=0;i<centroids.size();i++)
         {
            //conditions for sending a message
            int option = 0;
            boolean SendToOne = false;
            boolean SendMessage = false;
            int SendMessageTo = -1;
            double EdgeDelay = 0.0;
            Point p = this.FindNearestPoint(this.X_ic[i], RefPoints);
            for( int k= 0; k<nbors.size(); k++)
            {
                SendMessage = false;
                SendMessageTo = -1;
                option = -1;
                if (!this.CheckInsideRegion(this.X_ic[i],p))
                {
                     if (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])
                         ||!this.CheckEqualSize(this.X_ic[i],this.X_iandjc[k][i]))
                     {
                        //flood the data
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        option = 1;
                     }
                }

                if (option ==-1 &&
                    this.CheckInsideRegion(this.X_ic[i],p) && this.X_inotjc[k][i].size==0 &&
                   (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])))
                    {
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        option = 2;
                    }
                //not a tie...Ki lies in a convex region
                if (option ==-1 && this.CheckInsideRegion(this.X_ic[i],p) &&
                   (!this.CheckInsideRegion(this.X_iandjc[k][i],p)
                   ||!this.CheckInsideRegion(this.X_inotjc[k][i],p)))
                    {
                        //send something less
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        option = 3;
                    }

                if (SendMessage)
                {
                    this.UpdateSij(k,i,this.PercentPointstoSend,option,p);

                    L2Msg = L2Msg.concat(CreateMessage(S_ijc[k][i], S_ijc[k][i].size, i,k));
                    L2Msg = L2Msg.concat("#"+SendMessageTo+"#"+(int)(EdgeDelay*1000.0)+"%");

                    SendToOne = true;
                    Num_CtrlMessages[i]++;

                    if (this.TIME>=this.LastL2MsgSent+this.IntervalofL2Msg)
                        this.UpdateAfterMsgSent(i,k);

                }
            }
//            if (SendToOne && this.TIME>=this.LastMsgSent+this.IntervalofMsg)
//                AppendFile(this.MsgFile, this.TIME+" "+i+" "+ String.valueOf(Num_CtrlMessages[i])+"\n");
        }


        //now sent the data if necessary (a heavy communication indeed)
        int NumRecvd=0;
        for (int j=0;j<this.nbors.size();j++)
        {
            if (this.flag[j] == 1)
            {
                NumRecvd++;
            }
        }

     //   this.AppendFile(this.XiFile, ""+this.TIME+" "+this.norm(this.X_ic[0])+"\n");
        int savedStatus = this.CorrectStatus;

        if (this.norm(this.X_ic[0])>this.epsilon)
            this.CorrectStatus = 1;
        else
            this.CorrectStatus = 0;

        if (this.CorrectStatus!=savedStatus)
            this.AppendFile(this.CorrectNessFile, ""+this.TIME+" "+this.CorrectStatus+"\n");

      //  this.AppendFile(XiFile, ""+this.TIME+" "+this.norm(this.X_ic[0])+"\n");
        String DataSet = "";
        String DataMsg = "";
        boolean ToSend = false;
        int index = -1;
        if (NumRecvd == this.nbors.size()-1)
        {
            for (int i=0;i<centroids.size();i++)
            {
                if (this.norm(this.X_ic[i])>=this.epsilon)
                {
                    ToSend = true;
                    DataSet = CreateDataSet();
                    break;
                }
            }
        }


        if (ToSend)
        {
            for (int j=0;j<this.nbors.size();j++)
            {
                if (this.flag[j]==-1)
                {
                    Neighbor n = (Neighbor)nbors.elementAt(j);
                    index = j;
                    DataMsg = DataMsg.concat(DataSet+"#"+n.getNumber()+"#"+(int)(n.getDelay()*1000.0)+"%");
                    this.Num_DataMessages=1;
//                    AppendFile(this.MsgFile,this.TIME+" "+ String.valueOf(Num_DataMessages)+"\n");
                    DataSetToSend = true;
                    if (!this.AlertFlag)
                    {
                        this.AlertFlag = true;
                        this.LastDataMsgAlert = this.TIME;
                    }
                }
            }
        }

        if (DataMsg.equals(""))
            this.AlertFlag = false;

        //now sent the msg depending on the conditions
        String Msg = "";

        //no meesage needs to be sent
        if (L2Msg.equals("")&&DataMsg.equals("")&&PassedCentroids.equals(""))
            Msg = "Empty Msg";

        //check for L2 msg
        if (!L2Msg.equals(""))
        {
            //check the time
            if (this.TIME>=this.LastL2MsgSent+this.IntervalofL2Msg)
            {
                Msg = Msg.concat(L2Msg);
                this.LastL2MsgSent = this.TIME;
            }
            else
            {
                int waitTime = this.IntervalofL2Msg + this.LastL2MsgSent - this.TIME;
                Msg = Msg.concat("Wait Msg#"+this.getNumber()+"#"+waitTime+"%");
            }

        }

        //check for Data msg
        if (this.AlertFlag)
        {
            if (this.TIME>=this.LastDataMsgAlert+this.IntervalofDataAlert)
            {
                Msg = Msg.concat(DataMsg);
                //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data sent by "+this.getNumber()+"\n");
                this.flag[index]=0;         // change to send
                this.AlertFlag = false;     //reset alert flag
            }
            else
            {
                int waitTime = this.LastDataMsgAlert + this.IntervalofDataAlert - this.TIME;
                Msg = Msg.concat("Wait Data Msg#"+this.getNumber()+"#"+waitTime+"%");
                //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Wake Up Data Sent by "+this.getNumber()+"\n");
            }
        }

        if (!PassedCentroids.equals(""))
            Msg = Msg.concat(PassedCentroids);
        iface.sendMessage(Msg,this.getNumber());
    }

    //when all the points are changed at one go
    public void AddPoint(int PercentPointstoReplace)
    {

        int PointstoReplace = this.SIZE_OF_DATABASE*PercentPointstoReplace/100;

        int PointAddto = r.nextInt(2);
        if (PointAddto==0)
        {
            for (int i=0;i<PointstoReplace;i++)
                this.S_it.removeElementAt(0);

            for (int i=0;i<PointstoReplace;i++)
            {
                dg.GenPoint(this.NUM_CENTROIDS,this.NoiseProb,this.TIME);
                Point p = dg.GetPoint();
                this.S_it.add(p);
            }
        }
        else
        {
            for (int i=0;i<PointstoReplace;i++)
                this.DataTransferBuffer.removeElementAt(0);

            for (int i=0;i<PointstoReplace;i++)
            {
                dg.GenPoint(this.NUM_CENTROIDS,this.NoiseProb,this.TIME);
                Point p = dg.GetPoint();
                this.DataTransferBuffer.add(p);
            }
        }

        if (PointAddto==0)
        {
            for (int i=0;i<this.centroids.size();i++)
                this.S_itc[i].removeAllElements();

            Vector DummyVector = new Vector();
            for (int i=0;i<S_it.size();i++)
            {
                Point a = (Point)S_it.elementAt(i);
                Point newpt = new Point(this.dimension);
                for (int j=0;j<this.dimension;j++)
                	newpt.x[j] = a.x[j];
                DummyVector.add(newpt);
            }


            //relabel the points
            for (int i=0;i<DummyVector.size();i++)
            {
                double RefDistance = Double.MAX_VALUE;
                int index = -1;
                Point a = (Point)DummyVector.elementAt(i);
                for (int j=0;j<this.centroids.size();j++)
                {
                    Point b = (Point)this.centroids.elementAt(j);
                    double distance = this.Distance(a,b);
                    if (distance < RefDistance)
                    {
                        RefDistance = distance;
                        index = j;
                    }
                }
                Point b = (Point)this.centroids.elementAt(index);
                for (int j=0;j<this.dimension;j++)
                	a.x[j] = a.x[j] - b.x[j];
                a.membership = index;
                S_itc[index].add(a);
            }



    //        this.AppendFile("c:\\CurrentDataBase.txt","For Peer "+this.getNumber()+"\n"+"At Time : "+this.TIME+"\n"+
    //            		this.MakeString(this.S_it)+"\n\n");


            for (int i=0;i<this.centroids.size();i++)
            {
                Point p = (Point)this.centroids.elementAt(i);
                double[] oldSi = new double[this.dimension];
                double[] newSi = new double[this.dimension];
                int oldSisize = 0;
                int newSisize = 0;

                oldSisize = this.S_itcavg[i].size;
                for (int j=0;j<this.dimension;j++)
                    oldSi[j] = this.S_itcavg[i].Avg.x[j];

                S_itcavg[i] = new AvgVector(S_itc[i],this.dimension);
                newSisize = this.S_itcavg[i].size;
                for (int j=0;j<this.dimension;j++)
                newSi[j] = this.S_itcavg[i].Avg.x[j];


                for (int j=0;j<this.dimension;j++)
                {
                    X_ic[i].size = S_itc[i].size();
                    for( int k= 0; k<nbors.size(); k++)
                            X_ic[i].size += S_jic[k][i].size;

                    X_ic[i].Avg.x[j] = S_itcavg[i].Avg.x[j]*S_itcavg[i].size;
                    for( int k= 0; k<nbors.size(); k++)
                            X_ic[i].Avg.x[j] += S_jic[k][i].Avg.x[j]*S_jic[k][i].size;

                    if ( X_ic[i].size!=0)
                            X_ic[i].Avg.x[j] /= X_ic[i].size;
                    else
                            X_ic[i].Avg.x[j] = 0.0;


                    if (String.valueOf(X_ic[i].Avg.x[j]).equals("NaN"))
                            X_ic[i].Avg.x[j] = 0.0;


                        //DEBUG BEGIN
           //     AppendFile("c:\\X_ic.txt",""+this.TIME+" "+MakeString(X_ic[i],0));
                        //DEBUG END

                for( int k= 0; k<nbors.size(); k++)
                        X_inotjc[k][i].size = X_ic[i].size - X_iandjc[k][i].size;

                for( int k= 0; k<nbors.size(); k++)
                {
                    Neighbor n = (Neighbor)nbors.elementAt(k);
                    if (X_inotjc[k][i].size!=0)
                    {
                            X_inotjc[k][i].Avg.x[j] = (X_ic[i].Avg.x[j] * X_ic[i].size -
                            X_iandjc[k][i].Avg.x[j] * X_iandjc[k][i].size)/
                            (X_inotjc[k][i].size);
                    }
                        else
                            X_inotjc[k][i].Avg.x[j] = 0.0;

                }
            }
            this.AppendFile("c:\\Quality"+i+".txt",""+this.TIME+" ");
            for (int j=0;j<this.dimension;j++)
                this.AppendFile("c:\\Quality"+i+".txt",String.valueOf(newSi[j]-oldSi[j])+" ");
            this.AppendFile("c:\\Quality"+i+".txt",String.valueOf(newSisize-oldSisize)+"\n");
        }

    //        if (this.TIME>10000)
    //        {
    //            this.AppendFile("c:\\Test.txt", "\n\n");
    //        }

            String L2Msg = "";
            for (int i=0;i<this.centroids.size();i++)
            {
                //conditions for sending a message
                int option = 0;
                boolean SendToOne = false;
                boolean SendMessage = false;
                int SendMessageTo = -1;
                double EdgeDelay = 0.0;
                Point p = this.FindNearestPoint(this.X_ic[i], RefPoints);
                for( int k= 0; k<nbors.size(); k++)
                {
                    SendMessage = false;
                    SendMessageTo = -1;
                    option = -1;

                    if (!this.CheckInsideRegion(this.X_ic[i],p))
                    {
                         if (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])
                             ||!this.CheckEqualSize(this.X_ic[i],this.X_iandjc[k][i]))
                         {
                            //flood the data
                            SendMessage = true;
                            Neighbor n = (Neighbor)nbors.elementAt(k);
                            SendMessageTo = n.getNumber();
                            EdgeDelay = n.getDelay();
                            option = 1;
                         }
                    }

                    if (option ==-1 && this.CheckInsideRegion(this.X_ic[i],p) &&
                        this.X_inotjc[k][i].size==0 &&
                       (!this.CheckEqualVector(this.X_ic[i],this.X_iandjc[k][i])))
                        {
                            SendMessage = true;
                            Neighbor n = (Neighbor)nbors.elementAt(k);
                            SendMessageTo = n.getNumber();
                            EdgeDelay = n.getDelay();
                            option = 2;
                        }
                    //not a tie...Ki lies in a convex region
                    if (option ==-1 && this.CheckInsideRegion(this.X_ic[i],p) &&
                       (!this.CheckInsideRegion(this.X_iandjc[k][i],p)
                        ||!this.CheckInsideRegion(this.X_inotjc[k][i],p)))
                    {
                        //send something less
                        SendMessage = true;
                        Neighbor n = (Neighbor)nbors.elementAt(k);
                        SendMessageTo = n.getNumber();
                        EdgeDelay = n.getDelay();
                        option = 3;
                    }

                    if (SendMessage)
                    {
                        this.UpdateSij(k,i,this.PercentPointstoSend,option,p);
                        if (S_ijc[k][i].size<0)
                        {
                            System.out.println("Problems in sending to "+SendMessageTo);
                            System.exit(0);
                        }

                        L2Msg = L2Msg.concat(CreateMessage(S_ijc[k][i], S_ijc[k][i].size, i,k));
                        L2Msg = L2Msg.concat("#"+SendMessageTo+"#"+(int)(EdgeDelay*1000.0)+"%");

                        SendToOne = true;

                        if (this.TIME>=this.LastL2MsgSent+this.IntervalofL2Msg)
                            this.UpdateAfterMsgSent(i,k);

                    }
                }
    //            if (SendToOne && this.TIME>=this.LastMsgSent+this.IntervalofMsg)
    //                AppendFile(this.MsgFile, this.TIME+" "+i+" "+String.valueOf(Num_CtrlMessages[i])+"\n");
            }



            for (int l=0;l<this.NUM_CENTROIDS;l++)
                Num_CtrlMessages[l] = 0;

            int NumRecvd=0;
            for (int j=0;j<this.nbors.size();j++)
            {
                if (this.flag[j] == 1)
                {
                    NumRecvd++;
                }
            }

           // this.AppendFile(this.XiFile, ""+this.TIME+" "+this.norm(this.X_ic[0])+"\n");
            int savedStatus = this.CorrectStatus;

            if (this.norm(this.X_ic[0])>this.epsilon)
                this.CorrectStatus = 1;
            else
                this.CorrectStatus = 0;

            if (this.CorrectStatus!=savedStatus)
                this.AppendFile(this.CorrectNessFile, ""+this.TIME+" "+this.CorrectStatus+"\n");

         //   this.AppendFile(XiFile, ""+this.TIME+" "+this.norm(this.X_ic[0])+"\n");
            String DataSet = "";
            boolean ToSend = false;

            if (NumRecvd == this.nbors.size()-1)
            {
                for (int k=0;k<centroids.size();k++)
                {
                    if (this.norm(this.X_ic[k])>=this.epsilon)
                    {
                        ToSend = true;
                        DataSet = CreateDataSet();
                        break;
                    }
                }
            }
            int index = -1;
            String DataMsg = "";
            boolean DataSetToSend = false;
            if (ToSend)
            {
                for (int j=0;j<this.nbors.size();j++)
                {
                    if (this.flag[j]==-1)
                    {
                        Neighbor n = (Neighbor)nbors.elementAt(j);
                        index = j;
                        DataMsg = DataMsg.concat(DataSet+"#"+n.getNumber()+"#"+(int)(n.getDelay()*1000.0)+"%");
                        this.Num_DataMessages=1;
                        //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data needs to be sent by "+this.getNumber()+"\n");
    //                    AppendFile(this.MsgFile,  this.TIME+" "+String.valueOf(Num_DataMessages)+"\n");
                        DataSetToSend = true;
                        if (!this.AlertFlag)
                        {
                            this.AlertFlag = true;
                            this.LastDataMsgAlert = this.TIME;
                        }
                    }
                }
            }

            if (DataMsg.equals(""))
                this.AlertFlag = false;

            //now sent the msg depending on the conditions
            String Msg = "";

            //no meesage needs to be sent
            if (L2Msg.equals("")&&DataMsg.equals(""))
                Msg = "Empty Msg";

            //check for L2 msg
            if (!L2Msg.equals(""))
            {
                //check the time
                if (this.TIME>=this.LastL2MsgSent+this.IntervalofL2Msg)
                {
                    Msg = Msg.concat(L2Msg);
                    this.LastL2MsgSent = this.TIME;
                }
                else
                {
                    int waitTime = this.IntervalofL2Msg + this.LastL2MsgSent - this.TIME;
                    Msg = Msg.concat("Wait Msg#"+this.getNumber()+"#"+waitTime+"%");
                }

            }

            //check for Data msg
            if (this.AlertFlag)
            {
                if (this.TIME>=this.LastDataMsgAlert+this.IntervalofDataAlert)
                {
                    Msg = Msg.concat(DataMsg);
                    //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Data sent by "+this.getNumber()+"\n");
                    this.flag[index]=0;         // change to send
                    this.AlertFlag = false;     //reset alert flag
                }
                else
                {
                    int waitTime = this.LastDataMsgAlert + this.IntervalofDataAlert - this.TIME;
                    Msg = Msg.concat("Wait Data Msg#"+this.getNumber()+"#"+waitTime+"%");
                    //this.AppendFile("c:\\WakeUpData.txt","Time: "+this.TIME+" Wake Up Data Sent by "+this.getNumber()+"\n");
                }
            }
            iface.sendMessage(Msg,this.getNumber());
        }
        else
        {
            String Msg = "Empty Msg";
            iface.sendMessage(Msg,this.getNumber());
        }
    }



    public  double norm(AvgVector a)
	{
		double dist = 0.0;
		for (int i=0;i<a.Avg.d;i++)
			dist += Math.pow(a.Avg.x[i],2);

		dist = Math.sqrt(dist);
		return dist;
	}

	public  double dot(Point a, AvgVector b)
	{
		double dot = 0.0;
		for (int i=0;i<a.d;i++)
			dot+=a.x[i]*b.Avg.x[i];
		return dot;
	}

    public  String MakeString(Vector Pts)
	{
		String Data = "";
		for (int i=0;i<Pts.size();i++)
		{
			Point dp = (Point)Pts.elementAt(i);
			for (int j=0;j<dp.d;j++)
				Data = Data.concat(Double.toString(dp.x[j])+" ");
			Data = Data.concat(Integer.toString(dp.membership)+"\n");
		}
		return Data;
	}

	public String MakeString(AvgVector Pts)
	{
		String Data = "";

		for (int j=0;j<Pts.Avg.d;j++)
			Data = Data.concat(Double.toString(Pts.Avg.x[j])+" ");
		Data = Data.concat(Integer.toString(Pts.size)+"\n");
		return Data;
	}

    public  void WriteFile(String filename,String fileData) {
        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(filename));

            out.write(fileData);
            out.close();
        }
        catch (IOException e) {
            System.out.println("Writing exception");
        }
    }

    public  void AppendFile(String filename,String fileData) {
        try {
            BufferedWriter out = new BufferedWriter(new FileWriter(filename,true));

            out.write(fileData);
            out.close();
        }
        catch (IOException e) {
            System.out.println("Writing exception");
        }
    }


    public boolean CheckForZero(AvgVector a)
	{
		boolean zero = true;
		for (int i=0;i<this.dimension;i++)
			if (a.Avg.x[i]!=0.0)
			{
				zero = false;
				break;
			}
		return zero;
	}

	public  boolean CheckForZero(Point a)
	{
		boolean zero = true;
		for (int i=0;i<this.dimension;i++)
			if (a.x[i]!=0.0)
			{
				zero = false;
				break;
			}
	 	return zero;
    }

    public  String CreateMessage(AvgVector a, int size, int centroid,int neighbor)
    {
            String Msg = "";
            for (int i=0;i<this.dimension;i++)
                    Msg = Msg.concat(String.valueOf(a.Avg.x[i])+" ");
            Msg = Msg.concat("\n");
            Msg = Msg.concat(String.valueOf(size)+"\n");
            Msg = Msg.concat(String.valueOf(centroid)+"\n");
            //    System.out.println(Msg);
            return Msg;
    }

    public  String FetchMessageComponents(String Msg)
    {
//        System.out.println("Msg as recvd : "+Msg);
            String[] result =  Msg.split("\n");
            StringTokenizer st = new StringTokenizer(result[0]," ");
            int index = -1;
            Neighbor n = null;
            //the third element is centroid
            //fourth is the neighbor no (this is different from the actual node num of the neighbor)
            //get the neighbor no


//        System.out.println("Msg Components");
//        System.out.println(result[0]);
//        System.out.println(result[1]);
//        System.out.println(result[2]);
//        System.out.println(result[3]);

//        this.AppendFile("c:\\MsgDebug.txt", ""+result[4]+"\n");

            int NeighborNum = Integer.parseInt(result[result.length-2]);
            for (int i=0;i<nbors.size();i++)
            {
                    n = (Neighbor)nbors.elementAt(i);
                    if (n.getNumber()==NeighborNum)
                    {
                            index = i;
                            break;
                    }
            }

            if (index!=-1)
            {
                    for (int i=0;i<this.dimension;i++)
                    {
                            String temp = st.nextToken();
                            S_jic[index][Integer.parseInt(result[2])].Avg.x[i] = Double.parseDouble(temp);
                    }
                    S_jic[index][Integer.parseInt(result[2])].size = Integer.parseInt(result[1]);
            }

//        this.AppendFile("c:\\MsgDebug.txt", ""+NeighborNum+" "+index+" "+result[2]+"\n");
//        this.AppendFile("c:\\MsgDebug.txt", ""+this.MakeString(this.S_jic[index][Integer.parseInt(result[2])],0)+"\n");

            return (result[2]+" "+result[4]);
    }

    public String CreateDataSet()
    {
        String Msg = "DataSet\n";
        Vector DummyVector = new Vector();
        DummyVector.addAll(this.CollectedData);
        DummyVector.addAll(this.DataTransferBuffer);

        for (int i=0;i<DummyVector.size();i++)
        {
            Point p = (Point)DummyVector.elementAt(i);
            for (int j=0;j<this.dimension;j++)
                Msg = Msg.concat(String.valueOf(p.x[j])+" ");
            Msg = Msg.concat(String.valueOf(p.membership)+"\n");
        }

        return Msg;
    }

    public String MakeCentroidString()
    {
        String Msg = "Centroid\n";
        for (int i=0;i<this.centroids.size();i++)
        {
                Point p = (Point)this.centroids.elementAt(i);
                for (int j=0;j<this.dimension;j++)
                        Msg = Msg.concat(String.valueOf(p.x[j])+" ");
                        Msg = Msg.concat("\n");
        }

//        this.AppendFile("c:\\Test.txt", ""+this.TIME+"\n");
//        this.AppendFile("c:\\Test.txt", "Node Num : "+this.getNumber()+"\n");
//        this.AppendFile("c:\\Test.txt", "DataCollection : "+this.DataCollectionRound+" "+"Centroid: "+this.RecvdRound+"\n\n");

        return Msg;
    }

    public void GetTime(String Message)
    {
        String[] result = Message.split("\n");
        this.TIME = Integer.parseInt(result[result.length-1]);
    }

    public void AccumulateRemoteData(String Message)
    {
        String[] result = Message.split("\n");
        for (int i=1;i<result.length-2;i++)
        {
            StringTokenizer st = new StringTokenizer(result[i]," ");
            double[] a = new double[this.dimension];
            for (int j=0;j<this.dimension;j++)
                a[j] = Double.parseDouble(st.nextToken());

            Point p = new Point(a,Integer.parseInt(st.nextToken()));
            this.CollectedData.add(p);
        }
        if (CollectedData.size()>this.NUM_NODES*this.SIZE_OF_DATABASE)
        {
            System.out.println("Size of Data Base is "+CollectedData.size());
            System.exit(0);
        }
    }

    public void FetchCentroids(String Message)
    {
        Vector Temp = new Vector();
        String[] result = Message.split("\n");

        for (int i=1;i<result.length-2;i++)
        {
            StringTokenizer st = new StringTokenizer(result[i]," ");
            double[] a = new double[this.dimension];
            for (int j=0;j<this.dimension;j++)
            {
                    a[j] = Double.parseDouble(st.nextToken());
            }
            Point p = new Point(a,-1);
            Point temp = new Point(this.dimension);
            for (int j=0;j<this.dimension;j++)
                    temp.x[j] = p.x[j];
            this.centroids.add(temp);
        }
    }

    public void PrintMsgStats(int option,int neighbor,Point u,int NeighborNo)
    {
//        this.AppendFile("c:\\MsgDebug.txt", ""+this.TIME+"\n");
//        this.AppendFile("c:\\MsgDebug.txt", "From : "+this.getNumber()+" To: "+NeighborNo+"\n");
//        this.AppendFile("c:\\MsgDebug.txt", "Msg Option : "+option+"\n");
//        this.AppendFile("c:\\MsgDebug.txt", "Xi = "+this.MakeString(this.X_ic[0],0)+"\n");
//        this.AppendFile("c:\\MsgDebug.txt", "Xiandj = "+this.MakeString(this.X_iandjc[neighbor][0],0)+"\n");
//        this.AppendFile("c:\\MsgDebug.txt", "Xinotj = "+this.MakeString(this.X_inotjc[neighbor][0],0)+"\n");
//        this.AppendFile("c:\\MsgDebug.txt", "Sij = "+this.MakeString(this.S_ijc[neighbor][0],0)+"\n");
//        this.AppendFile("c:\\MsgDebug.txt", "Sji = "+this.MakeString(this.S_jic[neighbor][0],0)+"\n");
//        this.AppendFile("c:\\MsgDebug.txt", "u.x = "+u.x+" u.y = "+u.y+"\n\n");
    }

    public void UpdateSij(int neighbor,int centroid, double Percent, int option,Point nearestpt)
    {
        int k = neighbor;
        int i = centroid;
        AvgVector X = new AvgVector (this.dimension);
        //new stuff
        if (option==1)
        {
            for (int j=0;j<this.dimension;j++)
            {
                if (X_ic[i].size - this.S_jic[k][i].size!=0)
                {
                    X.Avg.x[j] = (this.X_ic[i].Avg.x[j]*this.X_ic[i].size -
                                            this.S_jic[k][i].size*this.S_jic[k][i].Avg.x[j])
                                            /(X_ic[i].size - this.S_jic[k][i].size);
                }
                else
                    X.Avg.x[j] = 0.0;
            }
            //set the size of X
            X.size = this.X_ic[i].size - this.S_jic[k][i].size;
        }
        else
        {
            int w = 0;
            //set the vector X
            for (int j=0;j<this.dimension;j++)
            {
                if (X_ic[i].size - this.S_jic[k][i].size!=0)
                {
                    X.Avg.x[j] = (this.X_ic[i].Avg.x[j]*this.X_ic[i].size -
                                            this.S_jic[k][i].size*this.S_jic[k][i].Avg.x[j])
                                            /(X_ic[i].size - this.S_jic[k][i].size);
                }
                else
                    X.Avg.x[j] = 0.0;
            }
            //set the size of X
            X.size = this.X_ic[i].size - this.S_jic[k][i].size;
            w = X.size;
            AvgVector newA = new AvgVector(this.dimension);
            AvgVector newW = new AvgVector(this.dimension);

//            this.AppendFile("c:\\MsgDebug.txt", "Updating Xij\n");

            do
            {
                w = w/2;
                X.size = this.X_ic[i].size - this.S_jic[k][i].size - w;

                newA.size = X.size + this.S_jic[k][i].size;
                newW.size = this.X_ic[i].size - X.size - this.S_jic[k][i].size;
                for (int j=0;j<this.dimension;j++)
                {
                    newA.Avg.x[j] = (X.Avg.x[j] * X.size + S_jic[k][i].Avg.x[j] * S_jic[k][i].size)/
                                    (newA.size);

                    newW.Avg.x[j] = (this.X_ic[i].size * this.X_ic[i].Avg.x[j]
                                     - X.Avg.x[j] * X.size
                                     - S_jic[k][i].Avg.x[j] * S_jic[k][i].size)/
                                    (newW.size);
                }
//                System.out.println(this.CheckInsideRegion(newA,nearestpt));
//                System.out.println(this.CheckInsideRegion(newW,nearestpt));
//                System.out.println(w);
//                this.AppendFile("c:\\MsgDebug.txt", "X : "+this.MakeString(X)+"\n");
//                this.AppendFile("c:\\MsgDebug.txt", "First term : "+this.MakeString(newA)+"\n");
//                this.AppendFile("c:\\MsgDebug.txt", "Second term : "+this.MakeString(newW)+"\n");
            }
            while((!this.CheckInsideRegion(newA,nearestpt))
                   ||(!this.CheckInsideRegion(newW,nearestpt) && newW.size>0));
        }

        //set Sij
        this.S_ijc[k][i].size = X.size;
        for (int j=0;j<this.dimension;j++)
            this.S_ijc[k][i].Avg.x[j] = X.Avg.x[j];

        /*
        //old stuff
        double temp = Percent*(X_ic[i].size - this.S_jic[k][i].size)/100.0;
        S_ijc[k][i].size = (int)temp;
        for (int j=0;j<this.dimension;j++)
        {
            if (S_ijc[k][i].size!=0)
            {
                S_ijc[k][i].Avg.x[j] = (this.X_ic[i].Avg.x[j]*(this.S_ijc[k][i].size+this.S_jic[k][i].size) -
                            this.S_jic[k][i].size*this.S_jic[k][i].Avg.x[j])/S_ijc[k][i].size;
            }
            else
                S_ijc[k][i].Avg.x[j] = 0.0;

        }
	         **/
    }

	public void UpdateAfterMsgSent(int centroid, int neighbor)
	{
            //    this.AppendFile("c:\\MsgDebug.txt", "Update Called for : "+neighbor+"\n");
            int k = neighbor;
            int i = centroid;
            //Xiandj
            X_iandjc[k][i].size = S_ijc[k][i].size + S_jic[k][i].size;

            Neighbor n = (Neighbor)nbors.elementAt(k);
            for (int j=0;j<this.dimension;j++)
            {
                    if ( X_iandjc[k][i].size!=0)
                    {
                            X_iandjc[k][i].Avg.x[j] = (S_ijc[k][i].Avg.x[j] * S_ijc[k][i].size +
                            S_jic[k][i].Avg.x[j] * S_jic[k][i].size)/
                            (X_iandjc[k][i].size);

                    }
                    else
                            X_iandjc[k][i].Avg.x[j] = 0.0;

		//   AppendFile(DataPath+"X_iandjc\\"+"X_iandjc-"+n.getNumber()+i+".txt",MakeString(X_iandjc[k][i],0));
	//    this.AppendFile("c:\\MsgDebug.txt", "After Update Xiandj = "+this.MakeString(this.X_iandjc[neighbor][0],0)+"\n\n");
		//Xinotj
                    X_inotjc[k][i].size = X_ic[i].size - X_iandjc[k][i].size;

                    if (X_inotjc[k][i].size!=0)
                    {
                            X_inotjc[k][i].Avg.x[j] = (X_ic[i].Avg.x[j] * X_ic[i].size -
                            X_iandjc[k][i].Avg.x[j] * X_iandjc[k][i].size)/
                            (X_inotjc[k][i].size);
                    }
                    else
                            X_inotjc[k][i].Avg.x[j] = Double.MAX_VALUE;
            }
		//DEBUG BEGIN
		//DEBUG END
	}

	public double Distance(Point a, Point b)
	{
            double dist = 0.0;
            for (int i=0;i<a.d;i++)
                    dist += Math.pow(a.x[i]-b.x[i],2);

            dist = Math.sqrt(dist);
            return dist;
	}

	public double Distance(AvgVector a, Point b)
        {
            double dist = 0.0;
            for (int i=0;i<a.Avg.d;i++)
                dist += Math.pow(a.Avg.x[i]-b.x[i],2);

            dist = Math.sqrt(dist);
            return dist;
        }

        public boolean CheckEqualVector(AvgVector a, AvgVector b)
        {
            boolean equal = true;
            for (int i=0;i<a.Avg.d;i++)
            {
                if (a.Avg.x[i] != b.Avg.x[i])
                {
                    equal = false;
                    break;
                }
                else
                    continue;
            }
            return equal;
        }

        public boolean CheckEqualSize(AvgVector a, AvgVector b)
        {
            if (a.size!=b.size)
                return false;
            else
                return true;
        }

        public Point FindNearestPoint(AvgVector K, Vector RefPoints)
        {
            Point p = new Point(this.dimension);
            double min = Double.MAX_VALUE;
            int minindex = -1;
            for (int i=0;i<this.RefPoints.size();i++)
            {
                p = (Point)this.RefPoints.elementAt(i);
                double dist = this.Distance(K,p);
                if (dist < min)
                {
                    min = dist;
                    minindex = i;
                }
            }
            p = (Point)this.RefPoints.elementAt(minindex);
    //        for (int i=0;i<p.d;i++)
    //        {
    //            System.out.print(p.x[i]+" ");
    //        }
    //
    //        System.out.println();
            return p;
        }

        public boolean CheckInsideRegion(AvgVector a, Point p)
        {
            boolean insideshape = false;
            boolean circle = this.CheckForZero(p);
            if (circle)
            {
                //nearest point is a circle
                if (this.norm(a)<this.epsilon)
                {
                    //a is inside the circle
                    insideshape = true;
                }
            }
            else
            {
                //nearest point is a half plane
                //first find the vector u
                Point u = new Point(this.dimension);
                for (int i=0;i<this.dimension;i++)
                {
                    u.x[i] = p.x[i]/(2.0*this.epsilon);
                }
                if (this.dot(u,a)>=this.epsilon)
                {
                    //inside one of the half spaces
                    insideshape = true;
                }
            }
            return insideshape;
        }

    }
