############################################################################
##
#W  drawdclasses.gi                     Manuel Delgado <mdelgado@fc.up.pt>
#W                                      Jose Morais    <jjoao@netcabo.pt>
##
#H  @(#)$Id: drawdclasses.gi,v 0.992 $
##
#Y  Copyright (C)  2005,  CMUP, Universidade do Porto, Portugal
##
##
##--------------------------------------------------------------------------------
InstallGlobalFunction(DrawDClassOfElement, function(arg)
    local S, E, fich, D, dclass, dclass2,
          name, generators, generatorsx, len, len2, lens, tlen, is_partial, list, flag, flag3, zero, egg, colors,
          box, box2, box3, box8, box9, box10, box11, box12, idempots, list2,
          trans_list, trans_list2, trans_list3, retels,
          infp, outfp, line1, line2, str1, str2, x, alphabet, ret, genslen, el,
          cl, i, i1, i2, i3, j, k, l, m, n, o, p, T, c, num,
          path, gv, jlin, xlen,xs1,xs2,xi,xlistels,xl1,xl2,xp, xflag,
          powerizeWord;
    
    
    powerizeWord := function(w)
        local w2, c, j, a;
        
        w2 := [];
        c := 0;
        for j in [1..Length(w)] do
            if c = 0 then
                a := w[j];
                c := 1;
            elif w[j] = a then
                c := c + 1;
            else
                if c = 1 then
                    Add(w2, a);
                else
                    w2 := Concatenation(w2, [a], "^", String(c));
                fi;
                c := 1;
                a := w[j];
            fi;
        od;
        if c = 1 then
            Add(w2, a);
        else
            w2 := Concatenation(w2, [a], "^", String(c));
        fi;
        return(w2);
    end;
    ##  End of powerizeWord()  --
    
    
    if not IsSemigroup(arg[1]) then
        Error("The first argument must be a Semigroup");
    fi;
    S := arg[1];
    T := false;
    
    if not IsTransformation(AsList(S)[1]) then
        Print("I will work with an isomorphic transformation semigroup instead\n");
        S:= Range(IsomorphismTransformationSemigroup(S));
    fi;
    generators := GeneratorsOfSemigroup(S);
    genslen := Length(generators);
    tlen := DegreeOfTransformation(generators[1]);
    generatorsx := [];
    for el in generators do
        if not el = IdentityTransformation(tlen) then
            Add(generatorsx, el);
        fi;
    od;
    alphabet := "abcdefghijklmnopqrstuvwxyz";
    E := IdentityTransformation(tlen);
    if IsFpSemigroup(arg[1]) then
        if IsString(arg[2]) then
            c := arg[2][1];
            p := Position(alphabet, c);
            if p = fail then
                Error("Ilegal character in ", arg[2], ": ", c);
            elif p > genslen then
                Error("Character ", c, " in ", arg[2], " is greater than the number of generators");
            else
                m := generators[p];
            fi;
            flag := false;
            num := "";
            i := 2;
            while IsBound(arg[2][i]) do
                c := arg[2][i];
                if IsDigitChar(c) then
                    if flag then
                        Add(num, c);
                    else
                        Error("Parse error in ", arg[2], " position ", i);
                    fi;
                elif c = '^' then
                    flag := true;
                    num := "";
                else
                    if num = "" then
                        E := E * m;
                    else
                        E := E * m^Int(num);
                    fi;
                    p := Position(alphabet, c);
                    if p = fail then
                        Error("Ilegal character in ", arg[2], ": ", c);
                    elif p > genslen then
                        Error("Character ", c, " in ", arg[2], " is greater than the number of generators");
                    else
                        m := generators[p];
                    fi;
                    flag := false;
                fi;
                i := i + 1;
            od;
            if num = "" then
                E := E * m;
            else
                E := E * m^Int(num);
            fi;
        elif IsTransformation(arg[2]) then
            E := arg[2];
        else
            Error("The second argument must be a Transformation or a String");
        fi;
    elif IsFpMonoid(arg[1]) then
        if IsString(arg[2]) then
            c := arg[2][1];
            p := Position(alphabet, c);
            if p = fail then
                Error("Ilegal character in ", arg[2], ": ", c);
            elif p > genslen+1 then
                Error("Character ", c, " in ", arg[2], " is greater than the number of generators");
            else
                m := generators[p];
            fi;
            flag := false;
            num := "";
            i := 2;
            while IsBound(arg[2][i]) do
                c := arg[2][i];
                if IsDigitChar(c) then
                    if flag then
                        Add(num, c);
                    else
                        Error("Parse error in ", arg[2], " position ", i);
                    fi;
                elif c = '^' then
                    flag := true;
                    num := "";
                else
                    if num = "" then
                        E := E * m;
                    else
                        E := E * m^Int(num);
                    fi;
                    p := Position(alphabet, c);
                    if p = fail then
                        Error("Ilegal character in ", arg[2], ": ", c);
                    elif p > genslen then
                        Error("Character ", c, " in ", arg[2], " is greater than the number of generators");
                    else
                        m := generators[p+1];
                    fi;
                    flag := false;
                fi;
                i := i + 1;
            od;
            if num = "" then
                E := E * m;
            else
                E := E * m^Int(num);
            fi;
        elif IsTransformation(arg[2]) then
            E := arg[2];
        else
            Error("The second argument must be a Transformation or a String");
        fi;
    elif not IsTransformation(arg[2]) then
        Error("The second argument must be a Transformation");
    else
        E := arg[2];        
    fi;
    

    
    path := DirectoriesSystemPrograms();
    gv := Filename( path, "gv" );
    if gv = fail then
        gv := Filename( path, "ggv" );
        if gv = fail then
            Error("Please install gv or ggv");
        fi;
    fi;
    gv := Concatenation(gv, " ");
    

    trans_list := [];
    fich := "semigroup";
    for i in [3..Length(arg)] do
        if IsString(arg[i]) then
            if arg[i] = "" then
                fich := "semigroup";
            else
                fich := arg[i];
            fi;

        elif IsList(arg[i]) then
            if not ForAll(arg[i], e -> IsTransformation(e)) then
                Error("The list of elements must be a list of Transformations ", arg[i]);
            fi;
            Add(trans_list, arg[i]);
        elif i = Length(arg) and arg[i] = 1 then
            T := true;
        else
            Error("The arguments must be: <semigroup> [, list of elements]* [, file name]");
        fi;
    od;
    
    name := Filename(DirectoryTemporary(), Concatenation(fich, ".dot"));
    D := GreensDClassOfElement(S, E);
    
    ##  We will check if the Transformations are partial
    
    
    idempots := Idempotents(S);
    trans_list2 := [];
    m := 1;
    if T then
        for i in trans_list do
            trans_list2[m] := [];
            j := 1;
            for l in i do
                trans_list2[m][j] := [];
                list := ImageListOfTransformation(l);
                for k in list do
                    Add(trans_list2[m][j], k);
                od;
                j := j + 1;
            od;
            m := m + 1;
        od;
    else
        for i in trans_list do
            trans_list2[m] := [];
            for l in i do
                list := ImageListOfTransformation(l);
                Add(trans_list2[m], Transformation(list));
            od;
            m := m + 1;
        od;
    fi;
    dclass2 := Elements(D);
    dclass := [];
    j := 1;
    for i in dclass2 do
        dclass[j] := [];
        list := ImageListOfTransformation(i);
        for k in list do
            Add(dclass[j], k);
        od;
        j := j + 1;
    od;
    if m > 2 then
        trans_list3 := [];
        for i in [1..m-2] do
            Add(trans_list3, Difference(trans_list2[i], trans_list2[i+1]));
        od;
        Add(trans_list3, trans_list2[m-1]);
        colors := [];
        k := 0;
        for i in [ "0.980 ", "0.784 ", "0.588 ", "0.392 ", "0.196 " ] do
            for j in [1..6] do
                if j = 1 then
                    Add(colors, Concatenation(i, "0.500 0.600 setrgbcolor"));
                elif j = 2 then
                    Add(colors, Concatenation("0.500 ", i, "0.600 setrgbcolor"));
                elif j = 3 then
                    Add(colors, Concatenation("0.500 0.600 ", i, "setrgbcolor"));
                elif j = 4 then
                    Add(colors, Concatenation(i, i, "0.600 setrgbcolor"));
                elif j = 5 then
                    Add(colors, Concatenation(i, "0.500 ", i, "setrgbcolor"));
                elif j = 6 then
                    Add(colors, Concatenation("0.600 ", i, i, "setrgbcolor"));
                fi;
                k := k + 1;
                if k = m then
                    break;
                fi;
            od;
        od;
    else
        trans_list3 := trans_list2;
        colors := ["0.9920 0.500 0.600 setrgbcolor"];
    fi;
        
        
    is_partial := false;
    list := [];
    for i in generators do
        Add(list, ImageListOfTransformation(i));
    od;
    len := Length(generators);
    for i in [1..tlen] do
        flag := true;
        for j in [1..len] do
            if not list[j][i] = i then
                flag := false;
                break;
            fi;
        od;
        if flag then
            zero := i;
            is_partial := true;
            break;
        fi;
    od;
    if is_partial and T then
        for m in trans_list3 do
            for i in m do
                for j in [1..zero-1] do
                    if i[j] = zero then
                        i[j] := "_";
                    elif i[j] > zero then
                        i[j] := i[j]-1;
                    fi;
                od;
                for j in [zero+1..tlen] do
                    if i[j] = zero then
                        i[j-1] := "_";
                    elif i[j] > zero then
                        i[j-1] := i[j]-1;
                    fi;
                od;
                Unbind(i[tlen]);
            od;
        od;
    fi;
    
    PrintTo(name, "digraph  sgp {", "\ngraph [center=yes,ordering=out,orientation=landscape];\nnode [shape=record,height=.1,width=.1,fontname=\"Times-Italic\"];\nedge [color=cornflowerblue,arrowhead=none];\n");
    box := [];
    box2 := [];
    box3 := [];
    box11 := [];
    egg := EggBoxOfDClass(D);
    if T then
        for m in [1..Length(egg[1])] do
            box[m] := [];
            box2[m] := [];
            box3[m] := [];
            for k in [1..Length(egg)] do
                cl := egg[k][m];
                box[m][k] := List(Elements(cl), x -> ImageListOfTransformation(x));
                box2[m][k] := List(Elements(cl), x -> x in Idempotents(S));
                if is_partial then
                    box3[m][k] := [];
                    for o in box[m][k] do
                        list := [];
                        for p in [1..zero-1] do
                            if o[p] = zero then
                                Add(list, "_");
                            elif o[p] > zero then
                                Add(list, o[p]-1);
                            else
                                Add(list, o[p]);
                            fi;
                        od;
                        for p in [zero+1..tlen] do
                            if o[p] = zero then
                                Add(list, "_");
                            elif o[p] > zero then
                                Add(list, o[p]-1);
                            else
                                Add(list, o[p]);
                            fi;
                        od;
                        Add(box3[m][k], list);
                    od;
                fi;
            od;
        od;
        if is_partial then
            box := box3;
        fi;
        len := Length(box);
        len2 := Length(box[1]);
        ##  Order the columns lexicographically
        box8 := [];
        for j in [1..len] do
            Add(box8, [ShallowCopy(box[j][1][1]), j]);
        od;
        Sort(box8);
        box9 := [];
        box10 := [];
        for j in [1..len] do
            k := box8[j][2];
            box9[j] := StructuralCopy(box[k]);
            box10[j] := StructuralCopy(box2[k]);
        od;
        ##  Order the rows lexicographically
        box8 := [];
        for j in [1..len2] do
            Add(box8, [ShallowCopy(box[1][j][1]), j]);
        od;
        Sort(box8);
        for j in [1..len] do
            for m in [1..len2] do
                k := box8[m][2];
                box[j][m] := StructuralCopy(box9[j][k]);
                box2[j][m] := StructuralCopy(box10[j][k]);
            od;
        od;
    
        AppendTo(name, "1 [label=\"");
        j := 1;
        for i1 in [1..len] do
            n := box[i1];
            AppendTo(name, "{");
            k := 1;
            for i2 in [1..Length(n)] do
                o := n[i2];
                AppendTo(name, "{");
                for i3 in [1..Length(o)] do
                    p := o[i3];
                    str1 := String(p);
                    str2 := [];
                    for x in [1..Length(str1)] do
                        if str1[x] = '"' then
                        else
                           Add(str2, str1[x]);
                       fi;    
                    od;
                    if box2[i1][i2][i3] then  # It is an idempotent
                        AppendTo(name, "*", str2, "\\n");
                    else
                        AppendTo(name, str2, "\\n");
                    fi;
                od;
                if k = len2 then
                    AppendTo(name, "}");
                else
                    AppendTo(name, "}|");
                    k := k + 1;
                fi;
            od;
            if j = len then
                AppendTo(name, "}");
            else
                AppendTo(name, "}|");
                j := j + 1;
            fi;
        od;
    else
        retels := [[],[]];
        for m in [1..Length(egg[1])] do
            box[m] := [];
            box2[m] := [];
            box3[m] := [];
            box11[m] := [];
            for k in [1..Length(egg)] do
                cl := egg[k][m];
                list2 := Elements(cl);
                box[m][k] := List(list2, x -> ImageListOfTransformation(x));
                box2[m][k] := List(list2, x -> x in idempots);
                box11[m][k] := list2;
                if is_partial then
                    box3[m][k] := [];
                    for o in box[m][k] do
                        list := [];
                        for p in [1..zero-1] do
                            if o[p] = zero then
                                Add(list, "_");
                            elif o[p] > zero then
                                Add(list, o[p]-1);
                            else
                                Add(list, o[p]);
                            fi;
                        od;
                        for p in [zero+1..tlen] do
                            if o[p] = zero then
                                Add(list, "_");
                            elif o[p] > zero then
                                Add(list, o[p]-1);
                            else
                                Add(list, o[p]);
                            fi;
                        od;
                        Add(box3[m][k], list);
                    od;
                fi;
            od;
        od;
        if is_partial then
            box := box3;
        fi;
        len := Length(box);
        len2 := Length(box[1]);
        ##  Order the columns lexicographically
        box8 := [];
        for j in [1..len] do
            Add(box8, [ShallowCopy(box[j][1][1]), j]);
        od;
        Sort(box8);
        box9 := [];
        box10 := [];
        box12 := [];
        for j in [1..len] do
            k := box8[j][2];
            box9[j] := StructuralCopy(box[k]);
            box10[j] := StructuralCopy(box2[k]);
            box12[j] := StructuralCopy(box11[k]);
        od;
        ##  Order the rows lexicographically
        box8 := [];
        for j in [1..len2] do
            Add(box8, [ShallowCopy(box[1][j][1]), j]);
        od;
        Sort(box8);
        for j in [1..len] do
            for m in [1..len2] do
                k := box8[m][2];
                box[j][m] := StructuralCopy(box9[j][k]);
                box2[j][m] := StructuralCopy(box10[j][k]);
                box11[j][m] := StructuralCopy(box12[j][k]);
            od;
        od;
        
        AppendTo(name, "1 [label=\"");
        j := 1;
        for i1 in [1..len] do
            n := box[i1];
            AppendTo(name, "{");
            k := 1;
            for i2 in [1..Length(n)] do
                o := n[i2];
                AppendTo(name, "{");
                for i3 in [1..Length(o)] do
                    p := box11[i1][i2][i3];
                    if p = MultiplicativeNeutralElement(S) then
                        str1 := "1";
                    elif p = MultiplicativeZero(S) then
                        str1 := "0";
                    else
                        ret := SemigroupFactorization(S, p)[1];
                        str1 := [];
                        if genslen > 26 then
                            for el in ret do
                                str1 := Concatenation(str1, "a", Position(generatorsx, el));
                            od;
                        else
                            for el in ret do
                                Add(str1, alphabet[Position(generatorsx, el)]);
                            od;
                        fi;
                    fi;
                    Add(retels[1], p);
                    Add(retels[2], powerizeWord(str1));
                    if box2[i1][i2][i3] then  # It is an idempotent
                        AppendTo(name, "*", powerizeWord(str1), "\\n");
                    else
                        AppendTo(name, powerizeWord(str1), "\\n");
                    fi;
                od;
                if k = len2 then
                    AppendTo(name, "}");
                else
                    AppendTo(name, "}|");
                    k := k + 1;
                fi;
            od;
            if j = len then
                AppendTo(name, "}");
            else
                AppendTo(name, "}|");
                j := j + 1;
            fi;
        od;
    fi;
    AppendTo(name, "\"];\n}\n");
            
    Exec(Concatenation("dot -Tps ", name, " -o ", name, ".ps"));
    if not trans_list2 = [] then
        if T then
            infp := InputTextFile(Concatenation(name, ".ps"));
            outfp := OutputTextFile(Concatenation(name, ".color.ps"), false);
            for i in [1..230] do
                line1 := ReadLine(infp);
                WriteLine(outfp, line1);
            od;
            flag3 := false;
            lens := [];
            for i in trans_list3 do
                Set(i);
                Add(lens, Length(i));
            od;
            len := Length(trans_list3);
            
            xs1 := " alignedtext";
            
            xlistels := [];
            for i in [1..len] do
                for k in [1..lens[i]] do
                    str1 := String(trans_list3[i][k]);
                    j := "";
                    for x in [1..Length(str1)] do
                        if str1[x] = '"' then
                           else
                            Add(j, str1[x]);
                        fi;    
                    od;
                    AddSet(xlistels, [j,i]);
                od;
            od;
            
            xl1 := List(xlistels, el -> el[1]);
            xl2 := List(xlistels, el -> el[2]);
            
            xflag := false;
            
            while true do
                line2 := ReadLine(infp);
                if line2 = fail then
                    break;
                fi;
                
                if xflag then
                    if line2[1] = '[' or (line2[1] = 'e' and line2[2] = 'n' and line2[3] = 'd') then

                    else
                        WriteLine(outfp, "0.000 0.000 0.000 setrgbcolor");
                    fi;
                    xflag := false;
                fi;
                if line2 = "xshow\n" then
                    WriteLine(outfp, line2);
                    line2 := "0.000 0.000 0.000 setrgbcolor\n";
                fi;
                xlen := Length(line2);
                if xlen-13 > 0 and IsBound(line2[xlen-13]) and line2[xlen-13] = ')' then
                    for xi in [1..12] do
                        if IsBound(line2[xlen-13+xi]) and line2[xlen-13+xi] = xs1[xi] then
                        else
                            break;
                        fi;
                    od;
                    if xi = 12 then #match!
                        xi := xlen-14;
                        xs2 := [];
                        while not line2[xi] = '(' do
                            Add(xs2, line2[xi]);
                            xi := xi - 1;
                        od;
                        xs2 := Reversed(xs2);
                        if xs2[1] = '*' then
                            RemoveElmList(xs2,1);
                        fi;
                        if xs2 in xl1 then
                            xp := Position(xl1,xs2);
                            WriteLine(outfp, colors[xl2[xp]]);
                            RemoveElmList(xl1, xp);
                            RemoveElmList(xl2, xp);
                            xflag := true;
                        fi;
                    fi;
                    
                elif line2[1] = '(' then
                    xi := 2;
                    xs2 := [];
                    while not line2[xi] = ')' do
                        Add(xs2, line2[xi]);
                        xi := xi + 1;
                    od;
                    if xs2[1] = '*' then
                        RemoveElmList(xs2,1);
                    fi;
                    if xs2 in xl1 then
                        xp := Position(xl1,xs2);
                        WriteLine(outfp, colors[xl2[xp]]);
                        RemoveElmList(xl1, xp);
                        RemoveElmList(xl2, xp);
                        xflag := true;
                    fi;
                fi;
                WriteLine(outfp, line2);
            od;

            CloseStream(infp);
            CloseStream(outfp);
            Print(Concatenation("Displaying file: ", name, ".color.ps\n"));
            Exec(Concatenation(gv, name, ".color.ps &"));
        else
            infp := InputTextFile(Concatenation(name, ".ps"));
            outfp := OutputTextFile(Concatenation(name, ".color.ps"), false);
            for i in [1..230] do
                line1 := ReadLine(infp);
                WriteLine(outfp, line1);
            od;
            flag3 := false;
            lens := [];
            for i in trans_list3 do
                Set(i);
                Add(lens, Length(i));
            od;
            len := Length(trans_list3);
            
            xs1 := " alignedtext";
            
            xlistels := [];
            
            for i in [1..len] do
                for k in [1..lens[i]] do
                    j := trans_list3[i][k];
                    p := Position(retels[1], j);
                    if not p = fail then
                        if j in idempots then
                            j := Concatenation("*", retels[2][p]);
                        else
                            j := retels[2][p];
                        fi;
                        AddSet(xlistels, [j,i]);
                    fi;
                od;
            od;
            
            xl1 := List(xlistels, el -> el[1]);
            xl2 := List(xlistels, el -> el[2]);
            
            xflag := false;
            
            while true do
                line2 := ReadLine(infp);
                if line2 = fail then
                    break;
                fi;
                if xflag then
                    if line2[1] = '[' or (line2[1] = 'e' and line2[2] = 'n' and line2[3] = 'd') then
                        
                    else
                        WriteLine(outfp, "0.000 0.000 0.000 setrgbcolor");
                    fi;
                    xflag := false;
                fi;
                if line2 = "xshow\n" then
                    WriteLine(outfp, line2);
                    line2 := "0.000 0.000 0.000 setrgbcolor\n";
                fi;
                xlen := Length(line2);
                if xlen-13 > 0 and IsBound(line2[xlen-13]) and line2[xlen-13] = ')' then
                    for xi in [1..12] do
                        if IsBound(line2[xlen-13+xi]) and line2[xlen-13+xi] = xs1[xi] then
                        else
                            break;
                        fi;
                    od;
                    if xi = 12 then #match!
                        xi := xlen-14;
                        xs2 := [];
                        while not line2[xi] = '(' do
                            Add(xs2, line2[xi]);
                            xi := xi - 1;
                        od;
                        xs2 := Reversed(xs2);
                        if xs2 in xl1 then
                            xp := Position(xl1,xs2);
                            WriteLine(outfp, colors[xl2[xp]]);
                            RemoveElmList(xl1, xp);
                            RemoveElmList(xl2, xp);
                            xflag := true;
                        fi;
                    fi;
                    
                elif line2[1] = '(' then
                    xi := 2;
                    xs2 := [];
                    while not line2[xi] = ')' do
                        Add(xs2, line2[xi]);
                        xi := xi + 1;
                    od;
                    if xs2 in xl1 then
                        xp := Position(xl1,xs2);
                        WriteLine(outfp, colors[xl2[xp]]);
                        RemoveElmList(xl1, xp);
                        RemoveElmList(xl2, xp);
                        xflag := true;
                    fi;
                fi;
                WriteLine(outfp, line2);
            od;
            CloseStream(infp);
            CloseStream(outfp);
            Print(Concatenation("Displaying file: ", name, ".color.ps\n"));
            Exec(Concatenation(gv, name, ".color.ps &"));
        fi;
    else
        Print(Concatenation("Displaying file: ", name, ".ps\n"));
        Exec(Concatenation(gv, name, ".ps &"));
    fi;
end);

##--------------------------------------------------------------------------------
##--------------------------------------------------------------------------------

InstallGlobalFunction(DrawDClasses, function(arg)
    local S, fich, name,
          dclasses, jclasses, ord_jclasses, egg, generators, generatorsx, is_partial, trans_list, trans_list2, trans_list3,
          c, cl, i, i1, i2, i3, j, k, l, l1, m, n, o, p, flag, flag3, len, len2, tlen, lenb, lend, lens,
          box, box2, box3, box4, box5, box6, box7, box8, box9, box10, box11, box12, list, list2, zero, colors,
          val, visited, visited2, T, retels, idempots,
          infp, outfp, line1, line2, x, str1, str2, alphabet, ret, genslen, el, stx, px,
          path, gv, xlen,xs1,xs2,xi,xlistels,xl1,xl2,xp, xflag,
          powerizeWord;
    
    
    powerizeWord := function(w)
        local w2, c, j, a;
        
        w2 := [];
        c := 0;
        for j in [1..Length(w)] do
            if c = 0 then
                a := w[j];
                c := 1;
            elif w[j] = a then
                c := c + 1;
            else
                if c = 1 then
                    Add(w2, a);
                else
                    w2 := Concatenation(w2, [a], "^", String(c));
                fi;
                c := 1;
                a := w[j];
            fi;
        od;
        if c = 1 then
            Add(w2, a);
        else
            w2 := Concatenation(w2, [a], "^", String(c));
        fi;
        return(w2);
    end;
    ##  End of powerizeWord()  --
    
    
    if not IsBound(arg[1]) then
        Error("The first argument must be a semigroup");
    else
        S := arg[1];
    fi;
    if not IsSemigroup(S) then
        Error("The first argument must be a semigroup");
    fi;
    
    alphabet := "abcdefghijklmnopqrstuvwxyz";
    
    path := DirectoriesSystemPrograms();
    gv := Filename( path, "gv" );
    if gv = fail then
        gv := Filename( path, "ggv" );
        if gv = fail then
            Error("Please install gv or ggv");
        fi;
    fi;
    gv := Concatenation(gv, " ");
    
    T := false;
    trans_list := [];
    fich := "semigroup";
    for i in [2..Length(arg)] do
        if IsString(arg[i]) then
            if arg[i] = "" then
                fich := "semigroup";
            else
                fich := arg[i];
            fi;
        elif IsList(arg[i]) then
            if not ForAll(arg[i], e -> IsTransformation(e)) then
                Error("The list of elements must be a list of Transformations ", arg[i]);
            fi;
            Add(trans_list, arg[i]);
        elif i = Length(arg) and arg[i] = 1 then
            T := true;
        else
            Error("The arguments must be: <semigroup> [, list of elements]* [, file name]");
        fi;
    od;
    if not IsTransformation(AsList(S)[1]) then
        Print("I will work with an isomorphic transformation semigroup instead\n");
        S:= Range(IsomorphismTransformationSemigroup(S));
    fi;
    name := Filename(DirectoryTemporary(), Concatenation(fich, ".dot"));
    
    
    ##  We will check if the transformations are partial or total
    generators := GeneratorsOfSemigroup(S);
    genslen := Length(generators);
    tlen := DegreeOfTransformation(generators[1]);
    generatorsx := [];
    for el in generators do
        if not el = IdentityTransformation(tlen) then
            Add(generatorsx, el);
        fi;
    od;
    trans_list2 := [];
    m := 1;
    if T then
        for i in trans_list do
            trans_list2[m] := [];
            j := 1;
            for l in i do
                trans_list2[m][j] := [];
                list := ImageListOfTransformation(l);
                for k in list do
                    Add(trans_list2[m][j], k);
                od;
                j := j + 1;
            od;
            m := m + 1;
        od;
    else
        for i in trans_list do
            trans_list2[m] := [];
            for l in i do
                list := ImageListOfTransformation(l);
                Add(trans_list2[m], Transformation(list));
            od;
            m := m + 1;
        od;
    fi;
    if m > 2 then
        trans_list3 := [];
        for i in [1..m-2] do
            Add(trans_list3, Difference(trans_list2[i], trans_list2[i+1]));
        od;
        Add(trans_list3, trans_list2[m-1]);
        colors := [];
        k := 0;
        for i in [ "0.980 ", "0.784 ", "0.588 ", "0.392 ", "0.196 " ] do
            for j in [1..6] do
                if j = 1 then
                    Add(colors, Concatenation(i, "0.500 0.600 setrgbcolor"));
                elif j = 2 then
                    Add(colors, Concatenation("0.500 ", i, "0.600 setrgbcolor"));
                elif j = 3 then
                    Add(colors, Concatenation("0.500 0.600 ", i, "setrgbcolor"));
                elif j = 4 then
                    Add(colors, Concatenation(i, i, "0.600 setrgbcolor"));
                elif j = 5 then
                    Add(colors, Concatenation(i, "0.500 ", i, "setrgbcolor"));
                elif j = 6 then
                    Add(colors, Concatenation("0.600 ", i, i, "setrgbcolor"));
                fi;
                k := k + 1;
                if k = m then
                    break;
                fi;
            od;
        od;
    else
        trans_list3 := trans_list2;
        colors := ["0.9920 0.500 0.600 setrgbcolor"];
    fi;
    is_partial := false;
    list := [];
    for i in generators do
        Add(list, ImageListOfTransformation(i));
    od;
    len := Length(generators);
    for i in [1..tlen] do
        flag := true;
        for j in [1..len] do
            if not list[j][i] = i then
                flag := false;
                break;
            fi;
        od;
        if flag then
            zero := i;
            is_partial := true;
            break;
        fi;
    od;
    if is_partial and T then
        for m in trans_list3 do
            for i in m do
                for j in [1..zero-1] do
                    if i[j] = zero then
                        i[j] := "_";
                    elif i[j] > zero then
                        i[j] := i[j]-1;
                    fi;
                od;
                for j in [zero+1..tlen] do
                    if i[j] = zero then
                        i[j-1] := "_";
                    elif i[j] > zero then
                        i[j-1] := i[j]-1;
                    fi;
                od;
                Unbind(i[tlen]);
            od;
        od;
    fi;
    
    ##  First we will order the D-classes by levels
    dclasses := GreensDClasses(S);
    lend := Length(dclasses);
    box4 := [];
    for i in [1..lend] do
        box4[i] := [];
        list := [1..lend];
        RemoveSet(list, i);
        for j in list do
            if IsGreensLessThanOrEqual(dclasses[i], dclasses[j]) then
                Add(box4[i], j);
            fi;
        od;
    od;
    visited := [];
    for i in [1..lend] do
        visited[i] := false;
    od;
    val := [];
    box5 := [];
    j := 1;
    while ForAny(visited, v -> v = false) do
        box5[j] := [];
        for i in [1..lend] do
            if ForAll(box4[i], a -> a in val) then
                Add(box5[j], i);
                visited[i] := true;
            fi;
        od;
        val := box5[j];
        j := j + 1;
    od;
    lenb := j - 1;
    list := ShallowCopy(box5[1]);
    for i in [2..lenb] do
        SubtractSet(box5[i], list);
        UniteSet(list, ShallowCopy(box5[i]));
    od;

    
    ##  Now we will write the dot file
    PrintTo(name, "digraph  sgp {", "\ngraph [center=yes,ordering=out,orientation=landscape];\nnode [shape=record,height=.1,width=.1,fontname=\"Times-Italic\"];\nedge [color=cornflowerblue,arrowhead=none];\n");
    idempots := Idempotents(S);        
    if T then        
        for l1 in box5 do        
            for i in l1 do
                box := [];
                box2 := [];
                box3 := [];
                c := dclasses[i];
                egg := EggBoxOfDClass(c);
                for m in [1..Length(egg[1])] do
                    box[m] := [];
                    box2[m] := [];
                    box3[m] := [];
                    for k in [1..Length(egg)] do
                        cl := egg[k][m];
                        list2 := Elements(cl);
                        box[m][k] := List(list2, x -> ImageListOfTransformation(x));
                        box2[m][k] := List(list2, x -> x in idempots);
                        if is_partial then
                            box3[m][k] := [];
                            for o in box[m][k] do
                                list := [];
                                for p in [1..zero-1] do
                                    if o[p] = zero then
                                        Add(list, "_");
                                    elif o[p] > zero then
                                        Add(list, o[p]-1);
                                    else
                                        Add(list, o[p]);
                                    fi;
                                od;
                                for p in [zero+1..tlen] do
                                    if o[p] = zero then
                                        Add(list, "_");
                                    elif o[p] > zero then
                                        Add(list, o[p]-1);
                                    else
                                        Add(list, o[p]);
                                    fi;
                                od;
                                Add(box3[m][k], list);
                            od;
                        fi;
                    od;
                od;
                if is_partial then
                    box := box3;
                fi;
                len := Length(box);
                len2 := Length(box[1]);
                ##  Order the columns lexicographically
                box8 := [];
                for j in [1..len] do
                    Add(box8, [ShallowCopy(box[j][1][1]), j]);
                od;
                Sort(box8);
                box9 := [];
                box10 := [];
                for j in [1..len] do
                    k := box8[j][2];
                    box9[j] := StructuralCopy(box[k]);
                    box10[j] := StructuralCopy(box2[k]);
                od;
                ##  Order the rows lexicographically
                box8 := [];
                for j in [1..len2] do
                    Add(box8, [ShallowCopy(box[1][j][1]), j]);
                od;
                Sort(box8);
                for j in [1..len] do
                    for m in [1..len2] do
                        k := box8[m][2];
                        box[j][m] := StructuralCopy(box9[j][k]);
                        box2[j][m] := StructuralCopy(box10[j][k]);
                    od;
                od;
            
                AppendTo(name, i, " [label=\"");
                j := 1;
                for i1 in [1..len] do
                    n := box[i1];
                    AppendTo(name, "{");
                    k := 1;
                    for i2 in [1..Length(n)] do
                        o := n[i2];
                        AppendTo(name, "{");
                        for i3 in [1..Length(o)] do
                            p := o[i3];
                            str1 := String(p);
                            str2 := [];
                            for x in [1..Length(str1)] do
                                if str1[x] = '"' then
                                else
                                   Add(str2, str1[x]);
                                fi;    
                            od;
                            if box2[i1][i2][i3] then  # It is an idempotent
                                AppendTo(name, "*", str2, "\\n");
                            else
                                AppendTo(name, str2, "\\n");
                            fi;
                        od;
                        if k = len2 then
                            AppendTo(name, "}");
                        else
                            AppendTo(name, "}|");
                            k := k + 1;
                        fi;
                    od;
                    if j = len then
                        AppendTo(name, "}");
                    else
                        AppendTo(name, "}|");
                        j := j + 1;
                    fi;
                od;
                AppendTo(name, "\"];\n");
            od;              
        od;
    else
        retels := [Elements(S), SemigroupFactorization(S, Elements(S)),[]];
        for l1 in box5 do        
            for i in l1 do
                box := [];
                box2 := [];
                box3 := [];
                box11 := [];
                c := dclasses[i];
                egg := EggBoxOfDClass(c);
                for m in [1..Length(egg[1])] do
                    box[m] := [];
                    box2[m] := [];
                    box3[m] := [];
                    box11[m] := [];
                    for k in [1..Length(egg)] do
                        cl := egg[k][m];
                        list2 := Elements(cl);
                        box[m][k] := List(StructuralCopy(list2), x -> ImageListOfTransformation(x));
                        box2[m][k] := List(StructuralCopy(list2), x -> x in idempots);
                        box11[m][k] := StructuralCopy(list2);
                        if is_partial then
                            box3[m][k] := [];
                            for o in box[m][k] do
                                list := [];
                                for p in [1..zero-1] do
                                    if o[p] = zero then
                                        Add(list, "_");
                                    elif o[p] > zero then
                                        Add(list, o[p]-1);
                                    else
                                        Add(list, o[p]);
                                    fi;
                                od;
                                for p in [zero+1..tlen] do
                                    if o[p] = zero then
                                        Add(list, "_");
                                    elif o[p] > zero then
                                        Add(list, o[p]-1);
                                    else
                                        Add(list, o[p]);
                                    fi;
                                od;
                                Add(box3[m][k], list);
                            od;
                        fi;
                    od;
                od;
                if is_partial then
                    box := box3;
                fi;
                len := Length(box);
                len2 := Length(box[1]);
                ##  Order the columns lexicographically
                box8 := [];
                for j in [1..len] do
                    Add(box8, [ShallowCopy(box[j][1][1]), j]);
                od;
                Sort(box8);
                box9 := [];
                box10 := [];
                box12 := [];
                for j in [1..len] do
                    k := box8[j][2];
                    box9[j] := StructuralCopy(box[k]);
                    box10[j] := StructuralCopy(box2[k]);
                    box12[j] := StructuralCopy(box11[k]);
                od;
                ##  Order the rows lexicographically
                box8 := [];
                for j in [1..len2] do
                    Add(box8, [ShallowCopy(box[1][j][1]), j]);
                od;
                Sort(box8);
                for j in [1..len] do
                    for m in [1..len2] do
                        k := box8[m][2];
                        box[j][m] := StructuralCopy(box9[j][k]);
                        box2[j][m] := StructuralCopy(box10[j][k]);
                        box11[j][m] := StructuralCopy(box12[j][k]);
                    od;
                od;
            
                AppendTo(name, i, " [label=\"");
                j := 1;
                for i1 in [1..len] do
                    n := box[i1];
                    AppendTo(name, "{");
                    k := 1;
                    for i2 in [1..Length(n)] do
                        o := n[i2];
                        AppendTo(name, "{");
                        for i3 in [1..Length(o)] do
                            p := box11[i1][i2][i3];
                            if p = MultiplicativeNeutralElement(S) then
                                str1 := "1";
                                retels[3][Position(retels[1], p)] := "1";
                            elif p = MultiplicativeZero(S) then
                                str1 := "0";
                                retels[3][Position(retels[1], p)] := "0";
                            else
                                px := Position(retels[1], p);
                                ret := retels[2][px];
                                str1 := [];
                                if genslen > 26 then
                                    for el in ret do
                                        str1 := Concatenation(str1, "a", Position(generatorsx, el));
                                    od;
                                else
                                    for el in ret do
                                        Add(str1, alphabet[Position(generatorsx, el)]);
                                    od;
                                fi;
                                str1 := powerizeWord(str1);
                                retels[3][px] := str1;
                            fi;
                            if box2[i1][i2][i3] then  # It is an idempotent
                                AppendTo(name, "*", str1, "\\n");
                            else
                                AppendTo(name, str1, "\\n");
                            fi;
                        od;
                        if k = len2 then
                            AppendTo(name, "}");
                        else
                            AppendTo(name, "}|");
                            k := k + 1;
                        fi;
                    od;
                    if j = len then
                        AppendTo(name, "}");
                    else
                        AppendTo(name, "}|");
                        j := j + 1;
                    fi;
                od;
                AppendTo(name, "\"];\n");
            od;              
        od;
    fi;

    ##  Draw the arrows
    box6 := [];
    box7 := [];
    for i in [1..lend] do
        box6[i] := [];
        box7[i] := [];
    od;
    for i in [1..lenb-1] do
        for j in box5[i] do
            for k in box5[i+1] do
                if IsGreensLessThanOrEqual(dclasses[k], dclasses[j]) then
                    AppendTo(name, j, "->", k, ";\n");
                    box7[k] := Set(Concatenation(box7[k], box7[j], [j]));
                    for l in box7[k] do
                        AddSet(box6[l], k);
                    od;
                fi;
            od;
        od;
    od;
    for i in [1..lenb-2] do
        for j in [i+2..lenb] do
            for k in box5[i] do
                for l in box5[j] do
                    if IsGreensLessThanOrEqual(dclasses[l], dclasses[k]) then
                        if not l in box6[k] then
                            AppendTo(name, k, "->", l, ";\n");
                            box7[l] := Set(Concatenation(box7[l], box7[k], [k]));
                            for m in box7[l] do
                                AddSet(box6[m], l);
                            od;
                        fi;
                    fi;
                od;
            od;
        od;
    od;
    AppendTo(name, "}\n");
    
    
    Exec(Concatenation("dot -Tps ", name, " -o ", name, ".ps"));
    if not trans_list2 = [] then
        if T then
            infp := InputTextFile(Concatenation(name, ".ps"));
            outfp := OutputTextFile(Concatenation(name, ".color.ps"), false);
            for i in [1..230] do
                line1 := ReadLine(infp);
                WriteLine(outfp, line1);
            od;
            flag3 := false;
            lens := [];
            for i in trans_list3 do
                Set(i);
                Add(lens, Length(i));
            od;
            len := Length(trans_list3);
            
            xs1 := " alignedtext";
            
            xlistels := [];
            for i in [1..len] do
                for k in [1..lens[i]] do
                    str1 := String(trans_list3[i][k]);
                    j := "";
                    for x in [1..Length(str1)] do
                        if str1[x] = '"' then
                           else
                            Add(j, str1[x]);
                        fi;    
                    od;
                    AddSet(xlistels, [j,i]);
                od;
            od;
            
            xl1 := List(xlistels, el -> el[1]);
            xl2 := List(xlistels, el -> el[2]);

            xflag := false;
            
            while true do
                line2 := ReadLine(infp);
                if line2 = fail then
                    break;
                fi;
                if xflag then
                    if line2[1] = '[' or (line2[1] = 'e' and line2[2] = 'n' and line2[3] = 'd') then

                    else
                        WriteLine(outfp, "0.000 0.000 0.000 setrgbcolor");
                    fi;
                    xflag := false;
                fi;
                if line2 = "xshow\n" then
                    WriteLine(outfp, line2);
                    line2 := "0.000 0.000 0.000 setrgbcolor\n";
                fi;
                xlen := Length(line2);
                if xlen-13 > 0 and IsBound(line2[xlen-13]) and line2[xlen-13] = ')' then
                    for xi in [1..12] do
                        if IsBound(line2[xlen-13+xi]) and line2[xlen-13+xi] = xs1[xi] then
                        else
                            break;
                        fi;
                    od;
                    if xi = 12 then #match!
                        xi := xlen-14;
                        xs2 := [];
                        while not line2[xi] = '(' do
                            Add(xs2, line2[xi]);
                            xi := xi - 1;
                        od;
                        xs2 := Reversed(xs2);
                        if xs2[1] = '*' then
                            RemoveElmList(xs2,1);
                        fi;
                        if xs2 in xl1 then
                            xp := Position(xl1,xs2);
                            WriteLine(outfp, colors[xl2[xp]]);
                            RemoveElmList(xl1, xp);
                            RemoveElmList(xl2, xp);
                            xflag := true;
                        fi;
                    fi;
                    
                elif line2[1] = '(' then
                    xi := 2;
                    xs2 := [];
                    while not line2[xi] = ')' do
                        Add(xs2, line2[xi]);
                        xi := xi + 1;
                    od;
                    if xs2[1] = '*' then
                        RemoveElmList(xs2,1);
                    fi;
                    if xs2 in xl1 then
                        xp := Position(xl1,xs2);
                        WriteLine(outfp, colors[xl2[xp]]);
                        RemoveElmList(xl1, xp);
                        RemoveElmList(xl2, xp);
                        xflag := true;
                    fi;
                fi;
                WriteLine(outfp, line2);
            od;
            CloseStream(infp);
            CloseStream(outfp);
            Print(Concatenation("Displaying file: ", name, ".color.ps\n"));
            Exec(Concatenation(gv, name, ".color.ps &"));
        else
            infp := InputTextFile(Concatenation(name, ".ps"));
            outfp := OutputTextFile(Concatenation(name, ".color.ps"), false);
            for i in [1..230] do
                line1 := ReadLine(infp);
                WriteLine(outfp, line1);
            od;
            flag3 := false;
            lens := [];
            for i in trans_list3 do
                Set(i);
                Add(lens, Length(i));
            od;
            len := Length(trans_list3);
            xs1 := " alignedtext";
            
            xlistels := [];
            for i in [1..len] do
                for k in [1..lens[i]] do
                    j := trans_list3[i][k];
                    p := Position(retels[1], j);
                    if not p = fail then
                        if j in idempots then
                            j := Concatenation("*", retels[3][p]);
                        else
                            j := retels[3][p];
                        fi;
                        AddSet(xlistels, [j,i]);
                    fi;
                od;
            od;
            xl1 := List(xlistels, el -> el[1]);
            xl2 := List(xlistels, el -> el[2]);
            
            xflag := false;
            while true do
                line2 := ReadLine(infp);
                if line2 = fail then
                    break;
                fi;
                if xflag then
                    if line2[1] = '[' or (line2[1] = 'e' and line2[2] = 'n' and line2[3] = 'd') then
                        
                    else
                        WriteLine(outfp, "0.000 0.000 0.000 setrgbcolor");
                    fi;
                    xflag := false;
                fi;
                if line2 = "xshow\n" then
                    WriteLine(outfp, line2);
                    line2 := "0.000 0.000 0.000 setrgbcolor\n";
                fi;
                xlen := Length(line2);
                if xlen-13 > 0 and IsBound(line2[xlen-13]) and line2[xlen-13] = ')' then
                    for xi in [1..12] do
                        if IsBound(line2[xlen-13+xi]) and line2[xlen-13+xi] = xs1[xi] then
                        else
                            break;
                        fi;
                    od;
                    if xi = 12 then #match!
                        xi := xlen-14;
                        xs2 := [];
                        while not line2[xi] = '(' do
                            Add(xs2, line2[xi]);
                            xi := xi - 1;
                        od;
                        xs2 := Reversed(xs2);
                        if xs2 in xl1 then
                            xp := Position(xl1,xs2);
                            WriteLine(outfp, colors[xl2[xp]]);
                            RemoveElmList(xl1, xp);
                            RemoveElmList(xl2, xp);
                            xflag := true;
                        fi;
                    fi;
                    
                elif line2[1] = '(' then
                    xi := 2;
                    xs2 := [];
                    while not line2[xi] = ')' do
                        Add(xs2, line2[xi]);
                        xi := xi + 1;
                    od;
                    if xs2 in xl1 then
                        xp := Position(xl1,xs2);
                        WriteLine(outfp, colors[xl2[xp]]);
                        RemoveElmList(xl1, xp);
                        RemoveElmList(xl2, xp);
                        xflag := true;
                    fi;
                fi;
                WriteLine(outfp, line2);
                
            od;
            CloseStream(infp);
            CloseStream(outfp);
            Print(Concatenation("Displaying file: ", name, ".color.ps\n"));
            Exec(Concatenation(gv, name, ".color.ps &"));
        fi;
    else
        Print(Concatenation("Displaying file: ", name, ".ps\n"));
        Exec(Concatenation(gv, name, ".ps &"));
    fi;
end);
