/*
 * PostOffice.java
 *
 * Created on August 10, 2005, 10:19 AM
 */

package DDMT.Agents;
import java.util.*;
import java.io.*;
/**
 *
 * @author  kanishk1
 */
public class PostOffice 
{
    int factor = 100000;
    int POBoxSize = 21*factor;
    Vector nbors = new Vector();
    int numToReply = 200;
    int numNodes = 200;
    MsgBin[] MsgQueue = new MsgBin[POBoxSize];
    
    MsgElement Msg = new MsgElement();
    int GlobalTime = 1;
    int CurrBinLocation = 0;
    int PercentPointsToReplace = 4;
    int DataMsgCount = 0;
    int DataMsgAddedTo = 0;
    int TotalL2Msg = 0;
    int TotalDataMsg = 0;
    
    public PostOffice() 
    {
        for (int i=0;i<this.POBoxSize;i++)
        {
            MsgBin Dummy = new MsgBin();
            this.MsgQueue[i] = Dummy;
        }
        
        for (int i=0;i<this.POBoxSize;i++)
        {
            if (i%1000==0)
            {
                System.out.println(i);
                this.AddDataGenMessages(i);
            }
        }
    }
    
    
    
    public void reply(String m, int num)
    { 
    //    System.out.println(m);
        MsgBin CurrMsg = new MsgBin();
        if (m.startsWith("Initialization Msg"))
        {
            AddMessageToBin(m,num);
            numToReply--;
        }
        else
            if (m.startsWith("Empty Initialization Msg"))
            {
                numToReply--;
            }
        else
        {
            //received a message
//            if (m.startsWith("DataSet"))
//                System.out.println("DataSet Recvd");
//            else
//                if (m.startsWith("Centroid"))
//                    System.out.println("Centroid Recvd");
//                else
//                    System.out.println("Ordinary Msg Recvd");
            
            numToReply--;
            if (!m.startsWith("Empty Msg"))
            {
                AddMessageToBin(m,num);
            }
        }
//        System.out.println(this.numToReply);
    }
    
    public int LeftToReply()
    {
        return this.numToReply;
    }
    
    public void AddMessageToBin(String m,int Sender)
    {
//        System.out.println(m);
        MsgBin CurrMsg = new MsgBin();
        if (m.startsWith("Initialization Msg"))
        {
            String[] result = m.split("!");
            m = result[1];
        }
       
        //first split the messages using delimiter % and then split using the #
        String[] MsgList = m.split("%");
        
        for (int i=0;i<MsgList.length;i++)
        {
            String[] Temp = MsgList[i].split("#");
            
            if (Integer.parseInt(Temp[2])>this.POBoxSize)
            {
                System.out.println("The size of the delay is greater than buffer size "+Integer.parseInt(Temp[2]));
                System.exit(0);
            }
            else
            {
                this.Msg = new MsgElement(Temp[0],Integer.parseInt(Temp[1]),Sender);
                CurrMsg = this.MsgQueue[(Integer.parseInt(Temp[2])+this.CurrBinLocation)%this.POBoxSize];
                CurrMsg.PostOfficeBin.addElement(Msg);
                this.MsgQueue[(Integer.parseInt(Temp[2])+this.CurrBinLocation)%this.POBoxSize] = CurrMsg;
                if (!Temp[0].startsWith("Wait") && !Temp[0].startsWith("DataGen") && !Temp[0].startsWith("DataSet"))
                {
                    this.TotalL2Msg++;
                }
                if (Temp[0].startsWith("DataSet"))
                {
                    this.TotalDataMsg++;
                }
            }
        }
    }
    
    
    public void AddCollectDataMsg()
    {
        MsgBin CurrMsg = new MsgBin();
        CurrMsg = this.MsgQueue[(1+this.CurrBinLocation)%this.POBoxSize];

        boolean DataMsgPresent = false;

        for (int i=0;i<CurrMsg.PostOfficeBin.size();i++)
        {
            this.Msg = (MsgElement)CurrMsg.PostOfficeBin.elementAt(i);
            if (this.Msg.Msg.startsWith("CollectData"))
            {
                DataMsgPresent = true;
                break;
            }   
        }

        if (!DataMsgPresent)
        {
            for (int i=0;i<this.numNodes;i++)
            {
            //    Neighbor n = (Neighbor)nbors.elementAt(i);

                this.Msg = new MsgElement("CollectData\n",i,i);
                CurrMsg.PostOfficeBin.addElement(Msg);
            }
            this.MsgQueue[(1+this.CurrBinLocation)%this.POBoxSize] = CurrMsg;
            System.out.println("!!!!!!!!!!!!!!!!!!CollectData Messages added");
           // System.exit(0);
            
//            int x = (20+this.DataMsgAddedTo)%this.POBoxSize;
//            this.AppendFile("c:\\CurrBin.txt", "CurrBinLoc : "+this.CurrBinLocation+" DataGen Msg added to : "+x+"\n");         
        }
        this.DataMsgAddedTo = this.DataMsgAddedTo+10;
    }
    public void AddDataGenMessages(int Loc)
    {
        MsgBin CurrMsg = new MsgBin();
        CurrMsg = this.MsgQueue[Loc];

        boolean DataMsgPresent = false;

        for (int i=0;i<CurrMsg.PostOfficeBin.size();i++)
        {
            this.Msg = (MsgElement)CurrMsg.PostOfficeBin.elementAt(i);
            if (this.Msg.Msg.startsWith("DataGen"))
            {
                DataMsgPresent = true;
                break;
            }   
        }

        if (!DataMsgPresent)
        {
            for (int i=0;i<this.numNodes;i++)
            {
            //    Neighbor n = (Neighbor)nbors.elementAt(i);

                this.Msg = new MsgElement("DataGen "+this.PercentPointsToReplace+"\n",i,i);
                CurrMsg.PostOfficeBin.addElement(Msg);
            }
            this.MsgQueue[Loc] = CurrMsg;
            System.out.println("!!!!!!!!!!!!!!!!!!DataGen Messages added");
        }
        this.DataMsgAddedTo = this.DataMsgAddedTo+10;
    }
    
    public Vector SendMessages()
    {
        Vector MessagesToSend = new Vector();
        MsgBin CurrMsg = new MsgBin();
        if (numToReply == 0)
        {
            if (this.TotalL2Msg!=0)
                this.AppendFile("c:\\PoBoxL2Messages.txt", this.GlobalTime+" "+this.TotalL2Msg+"\n");
            
            if (this.TotalDataMsg!=0)
                this.AppendFile("c:\\PoBoxDataMessages.txt", this.GlobalTime+" "+this.TotalDataMsg+"\n");
            
            this.TotalL2Msg = 0;
            this.TotalDataMsg = 0;
            //all the messages have been received
            this.GlobalTime++;
            this.DataMsgCount++;
            
            CurrMsg = MsgQueue[this.CurrBinLocation];
            int currQueueProcessed = 0;
            int savedBinLoc = this.CurrBinLocation;
            while (CurrMsg.PostOfficeBin.size()==0 && currQueueProcessed<this.POBoxSize)
            {
                this.CurrBinLocation = (this.CurrBinLocation+1)%this.POBoxSize;
                CurrMsg = MsgQueue[this.CurrBinLocation];
                this.GlobalTime++;
                currQueueProcessed++;
            }
            
            for (int i=0;i<CurrMsg.PostOfficeBin.size();i++)
            {
                MsgElement msgelem = (MsgElement)CurrMsg.PostOfficeBin.elementAt(i);
                //add the sender
                msgelem.Msg = msgelem.Msg.concat(String.valueOf(msgelem.src)+"\n");
                //add the time stamp
                msgelem.Msg = msgelem.Msg.concat(String.valueOf(this.GlobalTime)+"\n");
                //return the list of messages to be sent at this time
                MessagesToSend.addElement(msgelem);
                numToReply++;
            }

            
            
            if (currQueueProcessed==this.POBoxSize)
            {
                this.CurrBinLocation = savedBinLoc+500;
                this.GlobalTime = savedBinLoc+500;
            }
            
//            if (this.DataMsgCount%1000==0 || currQueueProcessed == this.POBoxSize )  
//            {
//                this.AddDataGenMessages();
//            }
       
            this.CurrBinLocation = (this.CurrBinLocation+1)%this.POBoxSize;
            System.out.println(this.GlobalTime+" "+CurrMsg.PostOfficeBin.size());
            CurrMsg.PostOfficeBin.removeAllElements();
        }
        return MessagesToSend;
    }
    
    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 static void main(String[] args) 
    {
        // TODO code application logic here
    }
    
}
