package maths;

//import wprover.CMisc;

public class CharSet {
    final private static boolean DEBUG = false;
    private PolyBasic basic = PolyBasic.getInstance();
    private static CharSet charset = new CharSet();
    private static int REDUCE_LEN = 2;

    public static boolean debug() {
        return DEBUG;
    }

    public static CharSet getinstance() {
        return charset;
    }

    public long freemonos() {
        return 0;
    }

    public TPoly charset(TPoly pp) {
        TPoly rm, ch, chend, p, output;
        output = null;
        p = pp;
        rm = p;

        if (rm == null) return pp;
        pp = reduce1(pp);

        while (rm != null) {
            TPoly tp;
            ch = chend = tp = rm;

            int vra = basic.lv(tp.getPoly());
            tp = tp.getNext();
            if (tp == null) {
                output = basic.ppush(rm.getPoly(), output);
                break;
            }
            int v = basic.lv(tp.getPoly());

            while (vra == v) {
                chend = tp;
                tp = tp.getNext();
                if (tp == null)
                    break;
                v = basic.lv(tp.getPoly());
            }
            chend.setNext(null);
            rm = tp;


            if (ch == chend) {
                output = basic.ppush(ch.getPoly(), output);
            } else {
                TPoly poly = null;

                while (ch.getNext() != null) {
                    TMono divor = basic.getMinV(vra, ch);
                    do {
                        TMono out;
                        TMono div = ch.getPoly();
                        if (div == divor) continue;
                        out = basic.prem(div, basic.p_copy(divor));

                        int a = basic.lv(out);
                        if (a == 0) {
                            if (DEBUG) {
                                System.out.println("Condition redundancy---------------------:");
                                basic.print(div);
                                basic.print(divor);
                            }
                        } else if (vra > a)
                            rm = basic.ppush(out, rm);
                        else
                            poly = basic.addpoly(out, poly);
                    } while ((ch = ch.getNext()) != null);
                    if (poly == null) {
                        output = basic.ppush(divor, output);
                        break;
                    } else {
                        poly = basic.addpoly(divor, poly);
                        ch = poly;
                        poly = null;
                    }
                }

            }
        }

//        this.printpoly(output);
        reduce(output);
        TPoly tp = reverse(output);
        if (!cfinished(tp))
            tp = charset(tp);

        TPoly p1 = tp;
        while (p1 != null) {
            TMono m = p1.getPoly();
            basic.factor1(m);
            basic.coefgcd(m);
            p1 = p1.getNext();
        }
        return tp;
    }

    public TPoly reduce1(TPoly poly) // 1, 2, 3, 4, 5
    {
        poly = reverse(poly);
        reduce(poly);
        poly = reverse(poly);
        return poly;
    }

    public void reduce(TPoly poly) {    // n ,n-1,,,,,,, 1.
        TPoly p1 = poly;
        while (p1 != null) {
            TMono m = p1.poly;
            if (basic.plength(m) <= REDUCE_LEN) {
                TPoly tx = poly;
                while (tx != null && tx != p1) {
                    TMono m2 = tx.poly;
                    tx.poly = basic.prem(m2, basic.p_copy(m));
                    tx = tx.next;
                }
            }
            p1 = p1.next;
        }
    }


    public boolean cfinished(TPoly pp) {
        if (pp == null) return true;
        int a = basic.lv(pp.getPoly());
        pp = pp.getNext();
        while (pp != null) {
            int n = basic.lv(pp.getPoly());
            if (a == n)
                return false;
            else {
                a = n;
                pp = pp.getNext();
            }
        }
        return true;
    }

    public void printpoly(TPoly pp) {
        int i = 0;
        while (pp != null) {
            if (pp.getPoly() != null) {
                Integer s = new Integer(i);
                System.out.print("f" + s.toString() + "= ");
                basic.print(pp.getPoly());
                i++;
            }
            pp = pp.getNext();
        }
    }

    public static TPoly reverse(TPoly pp) {
        if (pp == null) return pp;
        TPoly out = null;

        while (pp != null) {
            TPoly p = pp;
            pp = pp.getNext();

            if (out == null) {
                out = p;
                out.setNext(null);
            } else {
                p.setNext(out);
                out = p;
            }
        }
        return out;

    }

    public TPoly pushpoly(TMono p, TPoly pp) {
        TPoly pt;

        pt = new TPoly();
        pt.setNext(pp);
        pt.setPoly(p);
        return pt;
    }

}
