namespace edu.neu.ccs.demeterf.http.server{

using edu.neu.ccs.demeterf.http.classes;
using edu.neu.ccs.demeterf.util;
using System.IO;
using System.Reflection;
using System.Net.Sockets;
using System;
using edu.neu.ccs.demeterf.lib;

/** Web Server Factory class */
public class Factory {
    private Factory(){}

    static bool verbose = false;

    /** Set to true in order to get Output for Server/Dispatch descisions. */
    public static void setVerbose(bool v){
        verbose = v;
    }

    public static void p(String s){
        if (verbose) {
            Console.WriteLine(" ** " + s);
        }
    }

    /**
     * Create a new Server using the given Handler. The {@link
     * edu.neu.ccs.demeterf.http.server.Server Server} annotation is
     * used to tag a class as an HTTP Server/Handler.  Within the
     * class, {@link edu.neu.ccs.demeterf.http.server.Port Port}
     * Annotation is used to mark the port (an instance variable) the
     * Server will listen on, which is bound (read) at Server creation
     * time.  Handler methods are annotated with {@link
     * edu.neu.ccs.demeterf.http.server.Path Path} to describe
     * responses to various Path requests. See {@link
     * edu.neu.ccs.demeterf.http.Test Test} for an Example.
     */
    public static ServerThread create(Object handler){
        return create(handler, false);
    }

    /** Create a Single/Multi-threaded Server */
    public static ServerThread create(Object handler, bool single){
        Type t = handler.GetType();
        if (!t.IsDefined(typeof(Server),true)){
            throw error("Cannot Create Server for unannotated class '" + t.Name + "'");
        }
        int port = getPort(t, handler);
        p("Server Port = " + port);
        return new ServerThread(port, single, ServerDispatch.create(handler));
    }

    /** Create a ServerDispatch for direct testing */
    public ServerDispatch localDispatcher(Object handler){
        return ServerDispatch.create(handler, ServerDispatch.MinimalFormals);
    }
    
    /** Get the Port number of the server handler instance */
    private static int getPort(Type t, Object server){
        foreach(FieldInfo ff in Util.getFieldArray(t)){
            if(ff.IsDefined(typeof(Port),true) &&
               (ff.FieldType.Equals(typeof(int)) || ff.FieldType.Equals(typeof(Int32)))){
                try{
                    return (int)ff.GetValue(server);
                }catch(Exception e){
                    throw error("Port Field '"+ff.Name+"' is not accessible in " + t.Name);
                }
            }
        }
        throw error("No Port Field found in " + t.Name);
    }
    /** Create a RuntimeException to throw with the given Message */
    public static Exception error(String s){ return new Exception(s); }
    /** Create a RuntimeException to throw with the given Cause */
    public static Exception error(Exception e){ return e; }
}

}