package wprover;

import java.util.Vector;
import java.awt.*;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.FileOutputStream;

public class CTrace extends CClass {
    private static final int MAX_POINT = 501;

    private CPoint point, po;
    private CClass oObj;

    private int Num = 40;
    private int[] PX, PY;
    private int Radius = 2;
    private boolean dlns;
    private final static int MAXLEN = 300;


    public CTrace(CPoint p) {
        super(CClass.TRACE);
        m_name = "Trace of " + p;
        PX = new int[MAX_POINT];
        PY = new int[MAX_POINT];
        point = p;
        Num = -1;
    }

    public CTrace(CPoint p, CPoint po, CLine o) {
        super(CClass.TRACE);
        m_name = "Locus of " + p + " when " + po + " is on" + o;
        PX = new int[MAX_POINT];
        PY = new int[MAX_POINT];
        point = p;
        this.po = po;
        oObj = o;
    }

    public CTrace(CPoint p, CPoint po, Circle o) {
        super(CClass.TRACE);
        m_name = "Locus of " + p + " when " + po + " is on" + o;
        PX = new int[MAX_POINT];
        PY = new int[MAX_POINT];
        point = p;
        this.po = po;
        oObj = o;
    }

    public boolean isTracePt(CPoint pt) {
        return point == pt && po == null && oObj == null;

    }


    public void setDLns(boolean r) {
        dlns = r;
    }

    public boolean isDrawLines() {
        return dlns;
    }

    public void setNumPts(int n) {
        if (n < MAX_POINT)
            Num = n;
        else Num = MAX_POINT;
    }

    public void draw(Graphics2D g2, boolean selected) {
        if (!isdraw()) return;

        int radius = Radius;

        if (selected) {
            g2.setColor(CMisc.SelectObjectColor);
            g2.setStroke(CMisc.SelectObjectStroke);
            radius = Radius + 2;

        } else
            setDraw(g2);

        for (int i = 0; i < Num; i++) {
            if (!dlns)
                g2.fillOval(PX[i] - radius / 2, PY[i] - radius / 2, radius, radius);
            if (dlns) {
                if (oObj != null && oObj.get_type() == CClass.CIRCLE)
                    drawALN(PX[i], PY[i], PX[(i + 1) % Num], PY[(i + 1) % Num], g2);
                else if (i < Num - 1)
                    drawALN(PX[i], PY[i], PX[(i + 1) % Num], PY[(i + 1) % Num], g2);
            }
        }
    }

    public void drawALN(int x, int y, int x1, int y1, Graphics2D g2) {

        if ((x1 < -0 || x1 > 1000) && (x < -0 || x > 1000))
            return;

        if ((y1 < -0 || y1 > 1000) && (y < -0 || y > 1000))
            return;

        int dx = x - x1;
        int dy = y - y1;
        if(dx > MAXLEN || dx < - MAXLEN || dy > MAXLEN || dy < -MAXLEN)
            return;

        g2.drawLine(x, y, x1, y1);
    }

    public void draw(Graphics2D g2) {
        draw(g2, false);
    }

    public String TypeString() {
        if (m_name == null) return "Trace";
        return "Trace " + m_name;
    }

    public String getDescription() {
        return "Trace " + point.TypeString();
    }

    public boolean select(double x, double y) {
        if (!isdraw()) return false;
        double r2 = CMisc.PIXEPS * CMisc.PIXEPS;

        for (int i = 0; i < Num; i++)
            if (Math.pow(PX[i] - x, 2) + Math.pow(PY[i] - y, 2) < r2)
                return true;
        return false;
    }

    public void move(double dx, double dy) {
        for (int i = 0; i < Num; i++) {
            PX[i] += dx;
            PY[i] += dy;
        }
    }

    public void SavePS(FileOutputStream fp, int stype) throws IOException {
        if (!visible) return;

         for (int i = 0; i < Num; i++) {
                    if (dlns) {
                if (oObj != null && oObj.get_type() == CClass.CIRCLE || i < Num -1)
                {

                    int pos1x = PX[i];
                    int pos1y = PY[i];
                    int pos2x = PX[(i + 1) % Num];
                    int pos2y = PY[(i + 1) % Num];


                        String st1 = pos1x + " " + -pos1y + " moveto " + pos2x + " " + -pos2y + " lineto \n";
                        fp.write(st1.getBytes());
                        String st3 = "Color" + m_color + " stroke\n";
                        fp.write(st3.getBytes());
                }

            }
        }
    }


    public void Save(DataOutputStream out) throws IOException {
        super.Save(out);
        out.writeInt(point.m_id);
        out.writeInt(Num);
        for (int i = 0; i < Num; i++) {
            out.writeInt(PX[i]);
            out.writeInt(PY[i]);
        }

//          private CPoint point, po;
//    private CClass oObj;
//
//    private int Num = 16;
//    private int[] PX, PY;
//    private int Radius = 2;
//    private boolean dlns;
        int oid, mid;
        oid = mid = -1;
        if (po != null)
            oid = po.m_id;
        if (oObj != null)
            mid = oObj.m_id;
        out.writeInt(oid);
        out.writeInt(mid);

        out.writeInt(Num);
        out.writeInt(Radius);
        out.writeBoolean(dlns);
    }

    public void Load(DataInputStream in, drawProcess dp) throws IOException {
        super.Load(in, dp);
        if (CMisc.version_load_now >= 0.011) {
            int id = in.readInt();
            point = dp.getPointById(id);
        }
        Num = in.readInt();
        for (int i = 0; i < Num; i++) {
            PX[i] = in.readInt();
            PY[i] = in.readInt();
        }
        if (CMisc.version_load_now >= 0.044) {
            int id = in.readInt();
            po = dp.getPointById(id);
            id = in.readInt();
            oObj = dp.getOjbectById(id);
            Num = in.readInt();
            Radius = in.readInt();
            dlns = in.readBoolean();
        }
    }

    ///////////////////////////////////////////////////////


    public void addTracePoint(int i, double x, double y) {
        PX[i] = (int) x;
        PY[i] = (int) y;
        if (x < 0 || y < 0) {
            int k = 0;
        }
        soft(i);

    }

    public void addTracePoint(int x, int y, int i) {
        PX[i] = x;
        PY[i] = y;
        soft(i);
    }

    public void addTracePoint(int x, int y) {

        for (int i = 0; i <= Num; i++)
            if (PX[i] == x && PY[i] == y)
                return;
        if (Num >= MAX_POINT - 1)
            return;

        Num++;
        PX[Num] = x;
        PY[Num] = y;
    }


    public void softEdge() {

        for (int i = 2; i < Num - 1; i++) {
            int x = PX[i];
            int y = PY[i];

            int x0 = PX[i + 1];
            int y0 = PY[i + 1];

            int x1 = PX[i - 1];
            int y1 = PY[i - 1];

            int mx = Math.abs(x1 - x0);
            int my = Math.abs(y1 - y0);


            if (Math.abs(x - x0) > mx && Math.abs(x - x1) > mx
                    || Math.abs(y - y0) > my && Math.abs(y - y1) > my) {
                PX[i] = (x0 + x1) / 2;
                PY[i] = (y0 + y1) / 2;

            }


        }
    }

    public void soft(int i) {
    }


    public void trans(double dx, double dy) {
        for (int i = 0; i < Num; i++) {
            PX[i] += dx;
            PY[i] += dy;
        }
    }

    public double Roud_length() {
        if (Num == 0) return 0.0;

        double len = 0;
        int x, y;
        x = y = 0;

        for (int i = 0; i < Num; i++) {
            if (i != 0)
                len += Math.sqrt((x - PX[i]) * (x - PX[i]) + (y - PY[i]) * (y - PY[i]));
            x = PX[i];
            y = PY[i];
        }
        len += Math.sqrt((x - PX[0]) * (x - PX[0]) + (y - PY[0]) * (y - PY[0]));
        return len;
    }

    int getPtxi(int i) {
        return PX[i];
    }

    int getPtyi(int i) {
        return PY[i];
    }

    public CPoint getPoint() {
        return point;
    }

    public CPoint getonPoint() {
        return po;
    }

    public CClass getOnObject() {
        return oObj;
    }

    public int getPointSize() {
        return Num;
    }


}
