/*
 * DataGen.java
 *
 * Created on May 31, 2005, 11:24 AM
 */

package DDMT.Nodes;
import java.util.*;
import java.lang.Object;
import java.util.*;
import java.io.*;

/**
 *
 * @author  kanishk1
 */
public class DataGen
{
    Vector pts = new Vector();
    Random random = new Random();
    int dimension;

    Point pt ;
    int k;

    double variance = 5.0;
    double[][] Cov;

    public DataGen(int d)
    {
        this.dimension = d;
        this.Cov = new double[this.dimension][this.dimension];

        //set up the covariacne matrix
        Random covgen = new Random();
        covgen.setSeed(1000);

        for (int i=0;i<this.dimension;i++)
            for (int j=0;j<this.dimension;j++)
            {
                if (i==j)
                    this.Cov[i][j] = 1.0;
                else
                    this.Cov[i][j] = covgen.nextDouble() + 2.0;
            }

        random.setSeed(System.currentTimeMillis());
        try
        {
            Thread.sleep(100);
        }
        catch (InterruptedException  e)
        {

        }
    }

    public DataGen(int dim,double NoiseProb,int k,int NumPoints ,String FileName)
    {
        this.dimension = dim;
        this.Cov = new double[this.dimension][this.dimension];
        this.k = k;
        //set up the covariacne matrix
        Random covgen = new Random();
        covgen.setSeed(1000);

        for (int i=0;i<this.dimension;i++)
            for (int j=0;j<this.dimension;j++)
            {
                if (i==j)
                    this.Cov[i][j] = 1.0;
                else
                    this.Cov[i][j] = covgen.nextDouble() + 2.0;
            }

        for (int i=0;i<NumPoints;i++)
        {
            this.GenPoint(this.k, NoiseProb, 1);
            Point p = (Point)this.GetPoint();
            pts.add(p);
            System.out.println(i);
        }

        for (int i=0;i<this.dimension;i++)
        {
            for (int j=0;j<this.dimension;j++)
                System.out.print(this.Cov[i][j]+" ");
            System.out.println();
        }
        
        double ForbeniousNorm = 0.0;
        for (int i=0;i<this.dimension;i++)
            for (int j=0;j<this.dimension;j++)
                ForbeniousNorm+=this.variance*this.variance*this.Cov[i][j]*this.Cov[i][j];
            
        System.out.println("FNorm : "+ ForbeniousNorm);
        
        FileOperations.WriteFile(FileName, this.pts);
    }

//      print points
//    public DataGen(int k)
//    {
//
//        double[] mu = new double[k];
//        double[] sigma = new double[k];
//
//        //fized value of mu and sigma for all peers
//        mu[0] = -2;
//
//        sigma[0] = 15.0;
//
//        pts.removeAllElements();
//        for (int i=0;i<10000;i++)
//        {
//            double choice = random.nextDouble();
//            //generate a noise or a distribution
//            if (choice<0.1)
//            {
//                double x = random.nextDouble();
//                double y = random.nextDouble();
//                x = 6*Math.sqrt(this.variance)*(x-1)+mu[0] + 3*Math.sqrt(this.variance);
//                y = 6*Math.sqrt(this.variance)*(y-1)+mu[0] + 3*Math.sqrt(this.variance);
//                this.pt = new Point(x,y,-1);
//                pts.add(pt);
//            }
//            else
//            {
//                    double tx = mu[0] + sigma[0]*random.nextGaussian();
//                    double ty = mu[0] + sigma[0]*random.nextGaussian();
//
//                    double x = tx - 2.0*ty;
//                    double y = -2.0*tx + ty;
//
//                    Point dp = new Point(x,y,-1);
//                    pts.add(dp);
//
//            }
//        }
//
//        FileOperations.WriteFile("c:\\CentralData2.txt", this.pts);
//    }

    public void GenPoint(int k, double NoiseProb, int ClockTick)
    {
        Random r = new Random();
        this.k = k;

        int factor = 100000;

        if (ClockTick<2*factor)
        {
            r.setSeed(1000);
	    this.GaussianInitInside(0.1,k,r);
        }
        else if (ClockTick>2*factor && ClockTick<4*factor)
       	{
            r.setSeed(3000);
            this.GaussianInitOutside(0.1,k,r);
        }
        else if (ClockTick>4*factor && ClockTick<6*factor)
       	{
            r.setSeed(1000);
            this.GaussianInitInside(0.1,k,r);
        }
        else if (ClockTick>6*factor && ClockTick<8*factor)
       	{
            r.setSeed(3000);
            this.GaussianInitOutside(0.1,k,r);

        }
        else if (ClockTick>8*factor && ClockTick<10*factor)
       	{
            r.setSeed(1000);
            this.GaussianInitInside(0.1,k,r);
        }
        else if (ClockTick>10*factor && ClockTick<12*factor)
       	{
            r.setSeed(3000);
            this.GaussianInitOutside(0.1,k,r);
        }
        else if (ClockTick>12*factor && ClockTick<14*factor)
       	{
            r.setSeed(3000);
            this.GaussianInitInside(0.1,k,r);
        }
        else if (ClockTick>14*factor && ClockTick<16*factor)
       	{
            r.setSeed(3000);
            this.GaussianInitOutside(0.1,k,r);
        }
        else if (ClockTick>16*factor && ClockTick<18*factor)
       	{
            r.setSeed(3000);
            this.GaussianInitInside(0.1,k,r);
        }
        else if (ClockTick>18*factor && ClockTick<20*factor)
       	{
            r.setSeed(3000);
            this.GaussianInitOutside(0.1,k,r);
        }
        else if (ClockTick>20*factor)
       	{
            r.setSeed(3000);
            this.GaussianInitInside(0.1,k,r);
        }
    }

    public void GaussianInitInside(double NoiseProb,int k,Random r)
    {
        Gaussian[] g = new Gaussian[k];
        for (int i=0;i<this.k;i++)
            g[i] = new Gaussian(this.dimension);

        for (int i=0;i<this.k;i++)
        {
            g[i] = new Gaussian(this.dimension);
            double xx = r.nextDouble();
            for (int j=0;j<this.dimension;j++)
            {
//                g[i].mu[j] = 10+20*(xx-1);
                g[i].mu[j] = 5;
                g[i].sigma[j] = Math.sqrt(this.variance);
            }
        }

        double choice = random.nextDouble();
        //generate a noise or a distribution
        if (choice<NoiseProb)
        {
            double[] a = new double[this.dimension];
            for (int j=0;j<this.dimension;j++)
            {
                a[j] = random.nextDouble();
                a[j] = 6*Math.sqrt(this.variance)*(a[j]-1)+g[0].mu[0] + 3*Math.sqrt(this.variance);
            }
            Point dp = new Point(a,-1);
            this.pt = dp;

        }
        else
        {
            int GaussianChoice = random.nextInt(k);

            double[] a = new double[this.dimension];
            for (int j=0;j<this.dimension;j++)
                a[j] = g[GaussianChoice].mu[j] + g[GaussianChoice].sigma[j]*random.nextGaussian();


            //effect of covariace term
            //no covariance for Closed Loop
//            double[] anew = new double[this.dimension];
//            for (int i=0;i<this.dimension;i++)
//                for (int j=0;j<this.dimension;j++)
//                {
//                    anew[i] += this.Cov[i][j]*a[j];
//                }

            //for debug
//            anew[0] = a[0] + a[1]*3.0;
//            anew[1] = a[0]*3.0 + a[1];

            Point dp = new Point(a,-1);
            this.pt = dp;

        }
    }

    public void GaussianInitOutside(double NoiseProb,int k, Random r)
    {
        Gaussian[] g = new Gaussian[k];
        for (int i=0;i<this.k;i++)
            g[i] = new Gaussian(this.dimension);

        for (int i=0;i<this.k;i++)
        {
            g[i] = new Gaussian(this.dimension);
            double xx = r.nextDouble();
            for (int j=0;j<this.dimension;j++)
            {
//                g[i].mu[j] = 10+20*(xx-1);
                g[i].mu[j] = -5;
                g[i].sigma[j] = Math.sqrt(this.variance);
            }
        }

        double choice = random.nextDouble();
        //generate a noise or a distribution
        if (choice<NoiseProb)
        {
            double[] a = new double[this.dimension];
            for (int j=0;j<this.dimension;j++)
            {
                a[j] = random.nextDouble();
                a[j] = 6*Math.sqrt(this.variance)*(a[j]-1)+g[0].mu[0] + 3*Math.sqrt(this.variance);
            }
            Point dp = new Point(a,-1);
            this.pt = dp;
        }
        else
        {
            int GaussianChoice = random.nextInt(k);

            double[] temp = new double[this.dimension];
            double[] a = new double[this.dimension];
            for (int j=0;j<this.dimension;j++)
                a[j] = g[GaussianChoice].mu[j] + g[GaussianChoice].sigma[j]*random.nextGaussian();

            //effect of covariace term
            //no covariance for Closed Loop
//            double[] anew = new double[this.dimension];
//            for (int i=0;i<this.dimension;i++)
//                for (int j=0;j<this.dimension;j++)
//                {
//                    double tempCov = this.Cov[i][j];
//                    if (i!=j)
//                        tempCov = -this.Cov[i][j];
//                    anew[i] += tempCov*a[j];
//                }

            //for debug
//            anew[0] = a[0] - a[1]*3.0;
//            anew[1] = -a[0]*3.0 + a[1];


            Point dp = new Point(a,-1);
            this.pt = dp;
        }
    }

    public DataGen(String InputFileName)
    {
        pts  = FileOperations.ReadFile(InputFileName);
    }

    public Vector GetPoints()
    {
        return pts;
    }

    public Point GetPoint()
    {
        return this.pt;
    }

    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 double[][] MatrixMultiply(double[][] a, double[][] b, int size)
    {
        double[][] result = new double[size][1];
        for (int i=0;i<size;i++)
            for (int j=0;j<1;j++)
            {
                for (int k=0;k<size;k++)
                    result[i][j] += a[i][k]*b[k][j];
            }
        return result;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        // TODO code application logic here
       DataGen dg = new DataGen(1);

    }
}
