/**
 * 1.0.0 = first version
 * 1.0.1 = (+) visualization of testset
 * 1.0.2 = (+) options in command line
 * 1.0.3 = (+) in X() and Y() int -> double, (+) Locale.US
 * 1.0.4 = (+) final int FMT
 * 1.0.5 = (+) -save option: save to *.png files
 * 1.0.6 = (+) final String title
 * 1.0.7 = (+) 2012.12.05: iMask = -i, oMask = -o, scaleTest = -scale
 * 1.0.8 = (+) 2012.12.05: BufferedImage
 * 1.0.9 = (+) 2013.04.27: VK_SPACE
 */

/**
 * Author: Sergey Kopeliovich (Burunduk30@gmail.com)
 */

import java.lang.*;
import java.util.*;
import java.io.*;
import java.math.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.color.*;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;

public class Visualizer
{
  final String title = "Visualizer for problem 'convexset'";

  String iMask = "%02d", oMask = "%02d.a";

  String inputName( int num )
  {
    return String.format(iMask, num); 
  }

  String outputName( int num )
  {
    return String.format(oMask, num); 
  }

  Frame fr;
  Random r = new Random();

  final int inf = (int)1e9;

  boolean saveToFile = false;
  boolean verbose = false;
  boolean scaleTest = false;
  int R = 5;
  int testNumber = 1;
  String fIn, fOut;

  /* Begin of User Data */   
  int n, k, x[], y[], is[], ind[];
  double per;
  Color colors[];
  /* End of User Data */   
  
  boolean res;
  double xmin = inf, xmax = -inf;
  double ymin = inf, ymax = -inf;
  Scanner in, ans;
  MyCanvas C;
  int W, H;
  double cx, cy, kx, ky;

  int X( double x )
  {
    return (int)Math.round(W / 2.0 + (x - cx) * kx);
  }

  int Y( double y )
  {
    return (int)Math.round(H / 2.0 - (y - cy) * ky);
  }

  double sqr( double x )
  {
    return x * x;
  }

  void AddP( double x, double y )
  {
    xmin = Math.min(xmin, x);
    ymin = Math.min(ymin, y);
    xmax = Math.max(xmax, x);
    ymax = Math.max(ymax, y);
  }

  void doSaveToFile( Canvas c, String fileName )
  {
    int W = c.getWidth();
    int H = c.getHeight();
    BufferedImage img = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB);
    c.paint(img.getGraphics());
    ImageWriter iw = ImageIO.getImageWritersByFormatName("png").next();
    try {
      iw.setOutput(ImageIO.createImageOutputStream(new File(fileName + ".png")));
      iw.write(img);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

  boolean nextSample( int dTest )
  {
    try
    {
      testNumber += dTest;
      testNumber = Math.max(testNumber, 0);

      fIn = inputName(testNumber);
      fOut = outputName(testNumber);

      in = new Scanner(new File(fIn));

      xmin = inf; xmax = -inf;
      ymin = inf; ymax = -inf;

      n = in.nextInt();
      k = in.nextInt();
      is = new int[n];
      for (int i = 0; i < n; i++)
        is[i] = 0;
      x = new int[n];
      y = new int[n];
      for (int i = 0; i < n; i++)
      {
        x[i] = in.nextInt();
        y[i] = in.nextInt();
        AddP(x[i], y[i]);
      }
    }
    catch (Exception e)
    {
      System.out.println("Failed on file '" + fIn + "' : " + e.getMessage());
      //e.printStackTrace();
      return false;
    }

    try
    {
      ans = new Scanner(new File(fOut));
      per = ans.nextDouble();
      ind = new int[k];
      for (int i = 0; i < k; i++)
        is[ind[i] = ans.nextInt() - 1] = 1;
      res = true;
    }
    catch (IOException e)
    {
      System.out.println("Can not read file '" + fOut + "' : " + e.getMessage());
      res = false;
    }
    catch (Exception e)
    {
      System.out.println("Error reading file '" + fOut + "' : " + e.getMessage());
      res = false;
    }

    xmin--; xmax++;
    ymin--; ymax++;

    C.repaint();
    C.invalidate();

    if (saveToFile)
    {
      System.out.println("Save file " + inputName(testNumber));
      doSaveToFile(C, inputName(testNumber));
    }
    return true;
  }

  public void CreateFrame() throws Exception
  {
    fr = new Frame(title);

    fr.setSize(fr.getMaximumSize());
    fr.addKeyListener(new KeyAdapter() {
      public void keyPressed( KeyEvent e ) {
        if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
          System.exit(0);
        if (e.getKeyCode() == KeyEvent.VK_SPACE)
        {
          C.repaint();
          C.invalidate();
        }
        if (e.getKeyCode() == KeyEvent.VK_RIGHT)
        {
          if (!nextSample(1))
            if (!nextSample(-1))
              System.exit(0);
        }
        if (e.getKeyCode() == KeyEvent.VK_LEFT)
        {
          if (!nextSample(-1))
            if (!nextSample(1))
              System.exit(0);
        }
      }
    });
    fr.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    
    C = new MyCanvas();
    fr.add(C);
    fr.doLayout();

    System.out.println("Show frame...");
    fr.show();

    if (!nextSample(0))
      System.exit(0);
    if (saveToFile)
    {
      while (nextSample(1))
        ;
      System.exit(0);
    }
    else
    {
      while (true)
        ;
    }
  }

  int randomRGB()
  {
    return 50 + r.nextInt(150);
  }

  Color randomColor()
  {
    return new Color(randomRGB(), randomRGB(), randomRGB());
  }

  Color invColor( Color c )
  {
    return new Color(255 - c.getRed(), 255 - c.getGreen(), 255 - c.getBlue());
  }

  Font font = new Font("Courier New", Font.BOLD, 12);

  void drawString( Graphics g, String s, int cx, int cy )
  {
    g.drawString(s, cx - (int)(3 * s.length()), cy + 4);
  }

  void drawStringBC( Color foreColor, Color backColor, Graphics g, String s, int cx, int cy )
  {
    g.setColor(backColor);
    drawString(g, s, cx - 1, cy - 1);
    g.setColor(foreColor);
    drawString(g, s, cx, cy);
  }

  public class MyCanvas extends Canvas
  {
    BufferedImage buf = null;
    int bufW = -1, bufH = -1;

    public void setSize( int w, int h )
    {
      this.bufW = w; 
      this.bufH = h;
      super.setSize(w, h);
      buf = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
      buf.createGraphics();
    }

    public void f( Graphics g )
    {
      cx = (xmin + xmax) * 0.5;
      cy = (ymin + ymax) * 0.5;
      kx = (double)W / (xmax - xmin) * 0.8;
      ky = (double)H / (ymax - ymin) * 0.8;
      if (!scaleTest)
        kx = ky = Math.min(kx, ky);

      g.setColor(Color.WHITE);
      g.fillRect(0, 0, W, H);
      g.setFont(font);

      g.setColor(new Color(150, 150, 150));
      if (res)
        for (int i = 0; i < k; i++)
          for (int j = 0; j < i; j++)
          {
            int a = ind[i];
            int b = ind[j];
            g.drawLine(X(x[a]), Y(y[a]), X(x[b]), Y(y[b]));
          }

      for (int i = 0; i < n; i++)
      {
        g.setColor(is[i] == 1 ? Color.RED : Color.BLUE);
        g.fillOval(X(x[i]) - R, Y(y[i]) - R, 2 * R, 2 * R);
      }

      int y = 20, W = 20;
      g.setColor(new Color(0, 150, 0));
      g.drawString("Test: (" + fIn + ", " + fOut + ")", 10, y); y += W;
      g.drawString("Press right-left arrows to view the next-previous tests...", 10, y); y += W;
      g.drawString(String.format("n = %d, k = %d, perimetr = %.2f", n, k, per), 10, y); y += W;
    }

    public void doF( Graphics g ) {
      W = getWidth();
      H = getHeight();
      //if (bufW != w)
      //  setSize(W, H);
      System.out.println("W = " + W + ", H = " + H);
      f(g);
    }

    public void paint( Graphics g ) {
      doF(g);
    }

    public void update( Graphics g ) {
      doF(g);
    }
  }

  void ensure( int i, int k, String[] args )
  {
    if (i + k >= args.length)
    {
      System.out.println("ArgumentError: option '" + args[i] + "' should have " + k + " parametrs");
      System.exit(1);
    }
  }

  public void run( String[] args ) throws Exception
  {
    Locale.setDefault(Locale.US);

    System.out.println("Visualization of testset [v.1.0.8]");
    System.out.println("Visualizes pair of files [" + inputName(1) + "," + outputName(1) + ".a ; " +
      inputName(2) + "," + outputName(2) + ".a ; ...]");
    System.out.println("Usage: [-t <test_number>] [-R <radius>] [-i <mask>] [-o <mask>] [-v] [-save] [-scale]");
    System.out.println("  -t - select the number of the first test [default = " + testNumber + "]");
    System.out.println("  -R - select radius of points [default = " + R + "]");
    System.out.println("  -i - select mask of input files [default = " + iMask + "]");
    System.out.println("  -o - select mask of output files [default = " + oMask + "]");
    System.out.println("  -v - verbose, show text [default = false]");
    System.out.println("  -save - only build images");
    System.out.println("  -scale - make sizeX = sizeY");
    System.out.println("");
    System.out.println("Example of usage: -t " + 3 + " -save -i %03d -o %03d.a");
    System.out.println("");

    int i = 0;
    while (i < args.length)
      if (args[i].equals("-t"))
      {
        ensure(i, 1, args);
        testNumber = Integer.valueOf(args[i + 1]);
        i += 2;
      }
      else if (args[i].equals("-v"))
      {
        verbose = true;
        i++;
      }
      else if (args[i].equals("-R"))
      {
        ensure(i, 1, args);
        R = Integer.valueOf(args[i + 1]);
        i += 2;
      }
      else if (args[i].equals("-i"))
      {
        iMask = args[i + 1];
        i += 2;
      }
      else if (args[i].equals("-o"))
      {
        oMask = args[i + 1];
        i += 2;
      }
      else if (args[i].equals("-save"))
      {
        saveToFile = true;
        i += 1;
      }
      else if (args[i].equals("-scale"))
      {
        scaleTest = true;
        i += 1;
      }
      else
      {
        System.out.println("ArgumentError: unknown option '" + args[i] + "'");
        System.exit(1);
      }

    CreateFrame();
  }

  static public void main( String[] args ) throws Exception
  {
    new Visualizer().run(args);
  }
}
