/**
 * @author
 *  Adam Rosenzweig - amr152
 *  Valerie Davidkova - vkd4
 *  Miqdad Mohammed - mm1723
 */


package CookieCutter.g0;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;

class Environment extends JPanel {
    static Environment main = null;

    private JFrame frame;

    class Element {
        Object object;
        Color color;
        boolean filled;

        Element( Object obj, int col ) {
            object = obj;
            filled = ( col & 0xff000000 ) != 0;
            if ( filled )
                color = new Color( col, true );
            else
                color = new Color( col & 0xffffff );
        }
    }

    Vector elements = new Vector();

    double xmin = -2, xmax = 5.0, ymin = -2.0, ymax = 5.0;
    int width, height;
    static int counter = 0;

    /** draw the panel*/

    public Environment( JFrame frame ) {
        this.frame = frame;
    }

    public void setRange( double x0, double x1, double y0, double y1 ) {
        xmin = x0;
        xmax = x1;
        ymin = y0;
        ymax = y1;
    }

    public static void setMain( Environment p ) {
        main = p;
    }

    public static void waitClick() {
        try
        {
            while ( counter <= 0 )
            {
                Thread.sleep( 50 );
            }
            counter--;
        }
        catch ( InterruptedException e )
        {
        }
    }

    int scaleX( double x ) {
        return (int)( (x - xmin) * width / (xmax-xmin) );
    }

    int scaleY( double y ) {
        return (int)( (ymax - y) * height / (ymax-ymin) );
    }

    int scaleXS( double w ) {
        return (int)( w * width / (xmax-xmin) );
    }

    int scaleYS( double h ) {
        return (int)( h * height / (ymax-ymin) );
    }

    public void clear() {
          elements = new Vector();
          repaint();
      }

    public void draw( Object obj, int color ) {
        elements.add( new Element( obj, color ) );

        repaint();
    }



    public void paintComponent( Graphics g ) {
        int dist = g.getFont().getSize();
        int line = 1;

        super.paintComponent( g );

        Insets insets = getInsets();
        width = getWidth() - insets.left - insets.right;
        height = getHeight() - insets.top - insets.bottom;

        Vector data = elements;

        for ( int i=0; i<data.size(); i++ )
        {
            Element ele = (Element) data.get( i );
            Object obj = ele.object;
            Color col = ele.color;

            g.setColor( col );

            if ( obj instanceof Location )
            {
                Location p = (Location) obj;
                g.drawRect( scaleX(p.x()), scaleY(p.y()), 1, 1 );
            }
            else if ( obj instanceof Connector )
            {
                Connector s = (Connector) obj;
                g.drawLine( scaleX(s.x0()), scaleY(s.y0()),
                            scaleX(s.x1()), scaleY(s.y1()) );
            }
            else if ( obj instanceof Cookie )
            {
                Cookie cooks = (Cookie) obj;
                int n = cooks.n();
                int[] x = new int[n];
                int[] y = new int[n];

                for ( int j=0; j<n; j++ )
                {
                    x[j] = scaleX(cooks.x(j));
                    y[j] = scaleY(cooks.y(j));
                }

                if ( ele.filled )
                    g.fillPolygon( x, y, n );
                else
                    g.drawPolygon( x, y, n );
            }
            else if ( obj instanceof Rectangle )
            {
                Rectangle r = (Rectangle)obj;
                if ( ele.filled )
                {
                    g.fillRect( scaleX(r.x0()), scaleY(r.y1()),
                                scaleXS(r.width()), scaleYS(r.height()) );
                }
                else
                {
                    g.drawRect( scaleX(r.x0()), scaleY(r.y1()),
                                scaleXS(r.width()), scaleYS(r.height()) );
                }
            }
            else if ( obj instanceof String )
            {
                g.drawString( (String)obj, 2, dist * line++ );
            }
        }
    }


    public static final Environment create( String title, int width, int height ) {
        try {
            UIManager.setLookAndFeel(
                UIManager.getCrossPlatformLookAndFeelClassName() );
        } catch (Exception e) {}

        JFrame frame = new JFrame( title );
        Environment pane = new Environment( frame );
        frame.getContentPane().add( pane, BorderLayout.CENTER );

        frame.addWindowListener(
            new WindowAdapter()
            {
                public void windowClosing( WindowEvent e ) {
                    counter = 1000;
                    System.exit(0);
                }
            });

        pane.addMouseListener(
            new MouseAdapter()
            {
                public void mouseClicked( MouseEvent e ) {
                    counter++;
                }
            } );

        pane.setPreferredSize( new Dimension( width, height ) );
        frame.pack();

        frame.setLocationRelativeTo( null );
        frame.setVisible( true );

        return pane;
    }


    public static String[] split(String delim, String str) {

        ArrayList list = new ArrayList();
        StringTokenizer st = new StringTokenizer( str, delim );

        while ( st.hasMoreTokens() )
            list.add( st.nextToken() );

        return (String[]) list.toArray( new String[0] );
    }


    private static  Cookie scanPolygon( StringBuffer sb ) {
        Vector vlist = new Vector();

        if (sb.length() <= 0)
            return null;

        String[] toks = split( ",\t\n ", new String(sb) );

        for ( int i=0; i<toks.length-1; i+=2 )
            vlist.add(
                new Location( Double.parseDouble(toks[i]),
                           Double.parseDouble(toks[i+1]) ) );

        if ( vlist.size() <= 0 )
            return null;

        return new Cookie( (Location[]) vlist.toArray( new Location[0] ) );
    }


    static Cookie[] readGameFile( String filename ) {
        StringBuffer sb = new StringBuffer();
        Vector vlist = new Vector();
        File file = new File( filename );

        if ( !file.exists() )
            return null;

        try
        {
            BufferedReader br = new BufferedReader( new FileReader(file) );

            String str;
            while ( ( str = br.readLine()) != null )
            {
                if ( str.length() < 1 )
                    continue;

                if ( str.charAt(0) == '#' )
                    continue;

                if ( str.charAt(0) == '!' )
                {
                    Cookie cooks = scanPolygon( sb );
                    if ( cooks != null )
                        vlist.add( cooks );
                    sb = new StringBuffer();
                    continue;
                }

                sb.append(str);
                sb.append("\n");
            }

            Cookie cooks = scanPolygon( sb );
            if ( cooks != null )
                vlist.add( cooks );

            return (Cookie[]) vlist.toArray( new Cookie[0] );
        }
        catch( Exception e )
        {
            e.printStackTrace();
        }

        return null;
    }

    private static String[] _cmp_text = {
        "equal", "greater than", "less than", "disjoint", "joint" };


    private static void tester( Environment pane, Cookie cooks0, Cookie cooks1,
                                  double x, double y,
                                  double dx, double dy,
                                  int index ) {

        pane.draw( cooks0.translate( x, y ), 0xa0a0a0 );
        pane.draw( cooks1.translate( x, y ), 0x808080 );

        Cookie[] ccookss = cooks0.crossify( cooks1 );

        if ( ccookss != null )
        {
            for ( int j=0; j<ccookss[0].n(); j++ )
                pane.draw(
                    ccookss[0].vertex(j).translate(x,y), 0x008000 );

            for ( int j=0; j<ccookss[1].n(); j++ )
                pane.draw(
                    ccookss[1].vertex(j).translate(x,y), 0x800000 );

            pane.draw( ccookss[0].translate( x+dx, y+dy ), 0x008000 );
            pane.draw( ccookss[1].translate( x+dx, y+dy ), 0x800000 );

            pane.draw( "Two modified cookies in relation: "
                       + index + ": "
                       + _cmp_text[ccookss[0].compare( ccookss[1] )], 0 );
        }
        else
        {
            pane.draw( "Two cookies in relation: "
                       + index + ": "
                       + _cmp_text[ cooks0.compare( cooks1 ) ], 0 );
        }

        Cookie[][] sets;
        try {
            sets = cooks0.cutsets( cooks1 );
        }
        catch (Group7Exception e)
        {
            sets = null;
        }

        if ( sets != null )
        {
            for ( int k=0; k<2; k++ )
            {
                System.out.println( "Set#" + k
                                    + " [" + sets[k].length + "]  " );

                for ( int j=0; j<sets[k].length; j++ )
                {
                    pane.draw(
                        sets[k][j].translate( x+2*dx, y+2*dy ),
                        k*0xff0000 + 0x1000080 + (j*255/sets[k].length) );
                    System.out.println( sets[k][j].toString() );
                }
            }
        }
    }

    public static void main( String[] args ) {
        Environment pane = create( "Cookie Pane", 620, 620 );
        Cookie[] cookss = null;
        main = pane;

        if ( 1 == args.length )
        {
            cookss = readGameFile( args[0] );
            if ( null == cookss )
                System.err.println( "File not found: " + args[0] );
        }

        if ( cookss == null )
        {
            cookss = new Cookie[] { new Cookie( new Location[] {
                new Location( 0.1, 0.1 ),
                new Location( 0.2, 1.2 ),
                new Location( 0.7, 0.3 ),
                new Location( -0.1, -0.5 ) } ) };
        }

        Rectangle rect = new Rectangle( 1, 3, 1, 1 );

        for ( int i=0; i<cookss.length; i++ )
        {
            pane.draw( rect, 0xffaa66 );
            Cookie cooks = cookss[i];

            pane.draw( "Cookie: " + cooks.toString(), 0 );

            StringBuffer sb = new StringBuffer( "Angles:" );
            for ( int j=0; j<cooks.n(); j++ )
            {
                sb.append( " " );
                sb.append( Plane.format( Math.toDegrees( cooks.angle(j) ) ) );
            }
            pane.draw( sb.toString(), 0 );
            pane.draw( "isValid(): " + cooks.isValid(), 0 );
            pane.draw( "isSimple(): " + cooks.isSimple(), 0 );
            pane.draw( "isNegative(): " + cooks.isNegative(), 0 );
            pane.draw( "isConvex(): " + cooks.isConvex(), 0 );

            Cookie cooks0 = cooks.translate( 1, 3 );

            pane.draw( cooks0, 0 );
            pane.draw( cooks0.rotate( 1, 3, 2*Math.PI*30/360 ), 0x20 );
            pane.draw( cooks0.rotate( 1, 3, 2*Math.PI*60/360 ), 0x40 );
            pane.draw( cooks0.rotate( 1, 3, 2*Math.PI*90/360 ), 0x60 );
            pane.draw( cooks0.rotate( 1, 3, 2*Math.PI*120/360 ), 0x80 );

            Cookie cooks1 = cooks.translate( 2, 3 );

            pane.draw( cooks1, 0 );
            pane.draw( cooks1.rotate( 3, 4, 2*Math.PI*30/360 ), 0x20 );
            pane.draw( cooks1.rotate( 3, 4, 2*Math.PI*60/360 ), 0x40 );
            pane.draw( cooks1.rotate( 3, 4, 2*Math.PI*90/360 ), 0x60 );
            pane.draw( cooks1.rotate( 3, 4, 2*Math.PI*120/360 ), 0x80 );

            Cookie cooks2 = cooks.rotate( 3, 3, -2*Math.PI*45/360 );
            pane.draw( cooks2, 0 );
            pane.draw( cooks2.dilate( 0.0001 ), 0x20);
            pane.draw( cooks2.dilate( 0.05 ), 0x40 );
            pane.draw( cooks2.dilate( 0.1 ), 0x60 );
            pane.draw( cooks2.dilate( 0.2 ), 0x80 );

            pane.draw( cooks0.center(), 0 );
            pane.draw( cooks0.centroid(), 0xffffff );
            pane.draw( cooks2.center(), 0 );
            pane.draw( cooks2.centroid(), 0xffffff );

            pane.draw( "Cookie rotation: " + cooks2.toString(), 0 );
            pane.draw( "Negative rotation: " + cooks2.isNegative(), 0 );

            cooks = cooks.abs();

            for ( int l=0; l<4; l++ )
            {
                int x = l%2*3-1, y= -l/2+2;
                Cookie cooks3 = cooks.rotate( 0, 0, Math.toRadians( 25 * l ) );


                tester( pane, cooks, cooks3, x, y, 1, 0, l );
            }


  Cookie tcooks0 = new Cookie( new Location[] { new Location(0.2054,0.4), new Location(2.6333,0.4), new Location(2.6333,0.6), new Location(0.4733,0.6), new Location(0.4733,0.5786) } );
  Cookie tcooks1 = new Cookie( new Location[] { new Location(0.0933,1.0747), new Location(0.0933,0.7786), new Location(0.4733,0.5253), new Location(0.4733,0.8214) } );

            tester( pane, tcooks0, tcooks1, -1, -2, 0, 1, 100 );

            waitClick();
            pane.clear();
        }
    }
}
