/* **********************************
 *   Output.java
 *     Various Output Configurations
 * **********************************/
package admin;

import edu.neu.ccs.demeterf.demfgen.lib.List;
import gen.*;
import java.text.DecimalFormat;
import java.io.*;

public abstract class Output{
    public static void main(String[] args){
        List<Pair<PlayerID,Double>> lst = List.buildlist(new List.Build<Pair<PlayerID,Double>>(){
            public Pair<PlayerID,Double> build(int i){
                return new Pair<PlayerID,Double>(new PlayerID(i),Math.random()*5-2);
            }
        }, 10);
        List<Player> ps = lst.map(new List.Map<Pair<PlayerID,Double>, Player>(){
            public Player map(Pair<PlayerID,Double> p){ return new Player(p.a, "PLAYER#"+p.a.print()); }
        });
        
        Output out = Output.htmlOutput(); 
        out.header();
        out.finishTable(new Accounts(lst), new Players(ps.pop(4)), new Players(ps));
        out.footer();
    }
    
    
    static DecimalFormat form = new DecimalFormat("0.0000");
    public static String[] superS = {"st","nd","rd","th"};
    public static String suffix(int place){ return superS[Math.min(3, place-1)]; }
    
    PrintStream out;
    protected Output(PrintStream o){ out = o; }
    public String vspace(){ return "\n"; }
    public void println(String s){ print(s+"\n"); }
    public abstract void playerStart();
    public abstract void playerEnd();
    public abstract void line(String s);
    public abstract void line(String s, String color);
    public abstract void print(String s);
    public abstract void header();
    public abstract void footer();
    public abstract void finishTable(Accounts accts, final Players finished, Players all);
    
    public void newRound(int i, int max){
        line(vspace()+"***** ROUND "+i+" of "+max+" *****"+vspace(),"blue");
    } 
    public void newOTRound(int i, int max)
    {
    	line(vspace()+"***** OVERTIME ROUND " +(i-max)+" of 2 *****"+vspace(), "blue");
    }
    /** Print a Timing result */
    public void time(String what, long start){
        line("** "+what+": "+form.format((System.currentTimeMillis()-start)/1000.0));
    }
    /** Print a Rule Violation Message */
    public void violation(String what, Player p){
        line(vspace()+vspace()+"***** Player "+p.id.id+" ("+p.name+
                ") has violated a rule! *****"+vspace(),"red");
        for(String s:what.split("\n"))
            line("***** "+s,"red");
        line("");         
    }
    protected static Output die(String f){
        System.err.println(" ** ERROR OPENING OUTPUT FILE: "+f);
        System.exit(1);
        return null;    
    }
    public static Output termOutput(){ return new TERM(); }
    public static Output termOutput(String file){
        try{ return new TERM(new PrintStream(new FileOutputStream(file)));
        }catch(IOException e){ return die(file); }
    }
    public static Output htmlOutput(){ return new HTML(); }
    public static Output htmlOutput(String file){
        try{ return new HTML(new PrintStream(new FileOutputStream(file)));
        }catch(IOException e){ return die(file); }
    }
    
    static class TERM extends Output{
        String indent;
        protected TERM(){ this(System.err); }
        protected TERM(PrintStream o){ super(o); }
        
        public void line(String s){ println(" "+s); }
        public void line(String s, String c){ line(s); }
        public void print(String s){ out.print(s); }
        String head(){ return ""; }
        public void footer(){ }
        public void header(){
            println(head());
            line("***** Competition Csu670 SDG Game *****","blue");
            line("***** Date: "+new java.util.Date()+" *****","blue");
            line("");
        }
        public void playerStart(){ indent += "     "; }
        public void playerEnd(){ indent = indent.substring(5); }
        public void finishTable(Accounts accts, final Players finished, final Players all){
            println("\n ***** Final Results! *****");
            final int maxName = all.players.fold(new List.Fold<Player, Integer>(){
                public Integer fold(Player p, Integer i){ return Math.max(p.name.length(), i); }
            }, 0);
            
            String table = accts.accounts.sort(new List.Comp<Pair<PlayerID,Double>>(){
                public boolean comp(Pair<PlayerID,Double> p, Pair<PlayerID,Double> q){
                    return !finished.contains(q.a) ||
                    (finished.contains(p.a) && p.b > q.b);
                }
            }).foldl(new List.Fold<Pair<PlayerID,Double>, String>(){
                int place = 0;
                public String fold(Pair<PlayerID,Double> p, String r){
                    String name = all.forID(p.a).name;
                    double balance = p.b;
                    String pstr = finished.contains(p.a)?
                            (balance >= 0)?(++place)+"^"+superS[Math.min(3, place-1)]:"Neg":"----";
                    return (r+"    "+pstr+
                            "   Player# "+p.a.print()+
                            "   "+pad(name, maxName)+
                            "     $ "+form.format(balance)+"\n");
                }
            }, "\n");
            println(table);
        }
        public String pad(String s, int len){ return (len <= s.length())?s:pad(s+" ",len); }
    }
    
    public static class HTML extends TERM{
        protected HTML(){ this(System.err); }
        protected HTML(PrintStream o){ super(o); }
        
        public String vspace(){ return "<br/>"; }
        public void line(String s){ println(s+"<br/>"); }
        public void line(String s, String c){ line("<span style='color:"+c+";'>"+s+"</span>"); }
        public String head(){
            return ("<html><head><title> Competition: "+new java.util.Date()+
                    "</title></head>\n<body>");
        }
        public void footer(){ println("\n</body></html>\n"); }
        
        protected static String wrap(String body, String tag){ return wrap(body,tag,"",false); }
        protected static String border(String body, String tag){
            return wrap(body,tag," style='border: 1px solid blue; padding:3px;'",false);    
        }
        private static String wrap(String body, String tag, String attr, boolean nl){
            return "<"+tag+attr+">"+(nl?"\n":"")+body+(nl?"\n":"")+"</"+tag+">";
        }
        public void playerStart(){ println("<blockquote style='border:dotted 1px blue'><pre>"); indent += "   "; }
        public void playerEnd(){ indent = indent.substring(3); println("</pre></blockquote>"); }
        
        public void finishTable(Accounts accts, final Players finished, final Players all){
            println("\n<hr align='left' width='400px'><blockquote>\n"+wrap("***** Final Results! *****","h3"));
            String table = accts.accounts.sort(new List.Comp<Pair<PlayerID,Double>>(){
                public boolean comp(Pair<PlayerID,Double> p, Pair<PlayerID,Double> q){
                    return !finished.contains(q.a) ||
                    (finished.contains(p.a) && p.b > q.b);
                }
            }).foldl(new List.Fold<Pair<PlayerID,Double>, String>(){
                int place = 0, n = 0;
                public String fold(Pair<PlayerID,Double> p, String r){
                    n++;
                    String name = all.forID(p.a).name;
                    double balance = p.b;
                    String pstr = finished.contains(p.a)?
                            (balance >= 0)?(++place)+wrap(superS[Math.min(3, place-1)],"sup"):"Neg":"----";
                    return r+"    "+wrap(
                            border(pstr,"td")+
                            border("Player# "+p.a.print(),"td")+
                            border(name,"td")+
                            border("$ "+form.format(balance),"td"),
                            "tr", (n%2==1)?" style='background:lightgray'":"",false)+"\n";
                }
            }, "\n");
            println(border(table,"table")+"\n</blockquote>\n");
        }
        
    }
}