package Moo.Utils;

import java.util.Vector;
import java.util.Arrays;
import java.awt.Graphics2D;
import java.awt.*;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.*;//Line2D.Double;

import ACUtils.geom.*;
import ACUtils.BK;
import ACUtils.dBase.*;

public class ACPhenotype
{
/*
 * The "internally coded, inheritable information", or Genotype, carried by all living organisms, 
 * holds the critical instructions that are used and interpreted by the cellular machinary of 
 * the cells to produce the "outward, physical manifestation", or Phenotype of the organism.
 * Thus, all the physical parts, the molecules, macromolecules, cells and other structures, 
 * are built and maintained by cells following the instructions give by the genotype. 
 * As these physical structures begin to act and interact with one another they can produce 
 * larger and more complex phenomena such as metabolism, energy utilization, tissues, organs, 
 * reflexes and behaviors; anything that is part of the observable structure, function or 
 * behavior of a living organism. 
 */
        private Color[] kleuren = {Color.blue, Color.red, Color.yellow, Color.orange, Color.magenta, Color.green, Color.cyan};

        private int[] dna;

        private int[] chroms = {4,16};
        private int[] chrom1, chrom2;
        public int aantalVertrekken;
  
/*
 * Array met coordinaten welke gedecodeerd zijn ui thet DNA
 */
        private xyzPoint[] coor;
/*
 * Oorpsrong van de graph
 */
        private xyzPoint p0 = new xyzPoint(0.0, 0.0, 0.0);
/*
 * Matric die de relatie tussen de verschillende vertrekken bevat
 */
        private ACMateriaal[] matLijst;
        private ACMateriaal materiaal;
        private Vector materialenLijst;
        private Graphics2D Canvas2D;
        private int[][] ConnectionMatrix = new int[2][8];

        public ACPhenotype()
        {
ConnectionMatrix[0][0]=1;
ConnectionMatrix[0][1]=1;
ConnectionMatrix[0][2]=1;
ConnectionMatrix[0][3]=1;
ConnectionMatrix[0][4]=0;
ConnectionMatrix[0][5]=0;
ConnectionMatrix[0][6]=0;
ConnectionMatrix[0][7]=0;

ConnectionMatrix[1][0]=0;
ConnectionMatrix[1][1]=0;
ConnectionMatrix[1][2]=0;
ConnectionMatrix[1][3]=0;
ConnectionMatrix[1][4]=1;
ConnectionMatrix[1][5]=1;
ConnectionMatrix[1][6]=1;
ConnectionMatrix[1][7]=1;

                aantalVertrekken = ConnectionMatrix.length; 
        }//null constructor

        public void setMatLijst(Vector MaterialenLijst)
        {
                this.materialenLijst = MaterialenLijst; 
        }//setMatLijst

        public Area getArea(int nr)
        {
                return( DecodeerDNA( nr ) );
        }//getAreaVector

        public ACMateriaal[] getWandOpbouw()
        {
                int maxLagen = chrom(1).length;
                matLijst = new ACMateriaal[ maxLagen ];
                for(int i = 0; i < maxLagen; i++)
                {
                        int nr = dna[i];
                        if( nr > materialenLijst.size()-1)
                                nr = 0;
                        matLijst[i] = (ACMateriaal)materialenLijst.get( nr );
                }
                return( matLijst );
        }//getWandOpbouw

        public void setDNA( int[] dna )
        {
                this.dna = dna;
                chrom2 = chrom(2);
                int aantal = (int)(chrom2.length / 2);
                coor = new xyzPoint[ aantal ];
                DNAtoCoor(dna);
        }//setDNA

        public void draw( Graphics2D g2 )
        {
                Canvas2D = g2;
                if(dna == null || ConnectionMatrix==null)
                        return;

                for(int vertrekNr = 0; vertrekNr < ConnectionMatrix.length; vertrekNr++)
                {
                        Area area = DecodeerDNA( vertrekNr );
                        g2.setColor( kleuren[vertrekNr+2] );
                        g2.fill(area);
                        g2.setColor( kleuren[vertrekNr] );
                        g2.draw( area );
                }
        }//draw

        public double getOpp(Area area)
        {
                Vector hoekpunten = new Vector();
                double[] coords = new double[6];
                int type;

                PathIterator iterator = area.getPathIterator(null);
                while( !iterator.isDone() )
                {
                        type = iterator.currentSegment(coords);
                        switch( type )
                        {
                                case PathIterator.SEG_MOVETO:
                                case PathIterator.SEG_LINETO:
//                              case PathIterator.SEG_CLOSE:
                                        hoekpunten.add( new xyzPoint(coords[0],coords[1]) );
System.out.println("X,Y = coor: "+coords[0]+" , "+coords[1] );
                                        break;
                        }
                        iterator.next();
                }

                if(hoekpunten.size() == 0)
                        return( 0.0 );

                int newAantal = hoekpunten.size() + 2;
                xyzPoint[] punten = new xyzPoint[newAantal];
                int npoints = hoekpunten.size();
                punten[0] = (xyzPoint)hoekpunten.get(npoints-1);
                for(int i = 0; i < npoints; i++)
                        punten[i+1] = (xyzPoint)hoekpunten.get(i);

                punten[npoints+1] = (xyzPoint)hoekpunten.get(0);
//for(int k=0; k < newAantal; k++)
//      System.out.println("X,Y: "+punten[k].getX()+" , "+punten[k].getY() );
/*
 * Tegen de klok in draaien is negatief
 * Met de klok mee draaien is positief
 */
                xyzPoint P, Pnext;
                double opp = 0;
                for( int i = 0; i < newAantal-1; i++)
                {
                        P = punten[i];
                        Pnext = punten[i+1];
                        opp = opp + ( Pnext.getX() - P.getX())*(P.getY() + Pnext.getY());
                }
                opp = opp ;// / (1000.0*1000.0);//van mm2 naar m2
                return((Math.abs(opp)/2.0) );
        }//getOpp

/*******************
 * Private functions
 *******************/
        private int[] chrom( int nr )
        {
                int[] chrom = new int[ chroms[nr-1] ];
                int start = 0;
                for(int i = 0; i < nr-1; i++)
                        start = start + chroms[i];

                for(int i = start; i < (start+chroms[nr-1]); i++)
                        chrom[i-start] = dna[i];

                return( chrom);
        }//chrom

        private void DNAtoCoor(int[] dna)
        {
/*
 * Vertaal de genes naar coordinaten, 
 * oneven genes zijn vertaalde lengte_eenheden, en de
 *   even genes zijn vertaalde hoek_eenheden
 */

                for(int i = 0; i < coor.length; i++)
                {
                        coor[i] = new xyzPoint(0,0,0);
                        coor[i].setX( BK.polarToCart(p0, chrom2[i*2]*BK.eenheidLengte, chrom2[i*2+1]*BK.eenheidHoek ).getX() );
                        coor[i].setY( BK.polarToCart(p0, chrom2[i*2]*BK.eenheidLengte, chrom2[i*2+1]*BK.eenheidHoek ).getY() );
                }
/*
coor[0]=new xyzPoint(0,0,0);
coor[1]=new xyzPoint(1000,0,0);
coor[2]=new xyzPoint(500,0,0);
coor[3]=new xyzPoint(500,1000,0);
coor[4]=new xyzPoint(1000,1000,0);
coor[5]=new xyzPoint(0,1000,0);
*/
        }//DNAtoCoor

        private Area DecodeerDNA( int vertrekNr)
        {
                int[] RoomConnectionMatrix = ConnectionMatrix[ vertrekNr ]; 
                GeneralPath p1 = new GeneralPath();
                Vector ppVec = new Vector();
                xyzPoint[] pp = new xyzPoint[1];
                double minY=9999999999.0;
                int j=0, minYindex=0, delIndex=0;

                for(int i = 0; i < RoomConnectionMatrix.length; i++)
                        if( RoomConnectionMatrix[i] == 1)
                        {
                                ppVec.add( coor[i] );
System.out.println("....: "+coor[i]);
                                if( coor[i].getY() <= minY)
                                {
                                        minY = coor[i].getY();
                                        minYindex = i;
                                        delIndex= j;
                                }
                                j++;
                        }

                ppVec.remove( delIndex );
                pp = (xyzPoint[])ppVec.toArray( pp );
                for(int k=0; k < pp.length; k++)
                        pp[k].setDraai(coor[minYindex]);

                Arrays.sort( pp );
/*
System.out.println("min Y: "+ coor[minYindex] );
for(int c=0; c<pp.length;c++)
        System.out.println(pp[c]);
*/
                p1.moveTo( (float)coor[minYindex].getX(), (float)coor[minYindex].getY());
System.out.println("0: "+coor[minYindex]);
                for(int i = 0; i < pp.length; i++)
{
System.out.println((i+1)+": "+pp[i]+"   rc.: "+rc(coor[minYindex], pp[i]) );
                        p1.lineTo( (float)pp[i].getX(), (float)pp[i].getY());
}
                p1.closePath();

                return( new Area( p1) ); 
        }//DecodeDNA
        private double rc(xyzPoint p0, xyzPoint p1)
        {
                double d2=90.0;
                double dx, dy;
                double xp,yp,zp;

                xp = p1.getX() - p0.getX();
                yp = p1.getY() - p0.getY();
                zp = p1.getX() - p0.getZ();
System.out.println("xp: "+xp+"   yp: "+yp);
                dx = xp;
                dy = yp;
                if(dx> 0 && dy > 0)
                        d2 = Math.tan(Math.abs(dy/dx));
                if(dx< 0 && dy > 0)
                        d2 = -Math.tan(Math.abs(dy/dx)) + Math.PI;
                if(dx< 0 && dy < 0)
                        d2 = Math.tan(Math.abs(dy/dx)) + Math.PI;
                if(dx> 0 && dy < 0)
                        d2 = -Math.tan(Math.abs(dy/dx)) + Math.PI*2;
                return( Math.toDegrees( d2) );

        }
}// einde class ACPhenotype   
