package web;

import java.util.HashMap;
import java.util.Map;
import junit.framework.Assert;
import org.junit.Test;
import scg.exception.MissingArgumentException;
import scg.tournament.Session;
import scg.tournament.TournamentManager;
import scg.tournament.Users;
import scg.web.WebPage;
import edu.neu.ccs.demeterf.http.classes.HTTPHead;
import edu.neu.ccs.demeterf.http.classes.HTTPReq;
import edu.neu.ccs.demeterf.http.classes.HTTPResp;
import edu.neu.ccs.demeterf.http.classes.MsgHead;
import edu.neu.ccs.demeterf.http.classes.ParseException;
import edu.neu.ccs.demeterf.http.classes.URL;
import edu.neu.ccs.demeterf.lib.List;

public class TestWebPage {
  private static final String URL_STR = "http://localhost/test";
  private static final String[] ARGS = new String[] {"arg0", "arg1", "arg2"};
  private static final String[] VALS = new String[] {"val0", "val1", "val2"};
  private static final String CONTENT = "some text";
  private static final String MAP_KEY = "a key";

  private static HTTPReq makeReq() throws ParseException {
    HTTPHead head = HTTPHead.Get(URL.parse(URL_STR));
    List<MsgHead> list = List.<MsgHead> create();
    return HTTPReq.create(head, list, "");
  }

  private static HTTPReq makeReqUrlArgs(String args) throws ParseException {
    HTTPHead head = HTTPHead.Get(URL.parse(URL_STR + "?" + args));
    List<MsgHead> list = List.<MsgHead> create();
    return HTTPReq.create(head, list, "");
  }

  private static HTTPReq makeReqPostArgs(String args) throws ParseException {
    HTTPHead head = HTTPHead.Get(URL.parse(URL_STR));
    List<MsgHead> list = List.<MsgHead> create();
    return HTTPReq.create(head, list, args);
  }

  private static TestableWebPage makeTesTableWebPage() throws ParseException {
    return new TestableWebPage(new TournamentManager(), makeReq(), new Users(""));
  }

  @Test
  public void builderAppendLnTest() throws ParseException {
    TestableWebPage page = makeTesTableWebPage();
    StringBuilder builder = new StringBuilder();
    page.exposeBuilderAppendLn(builder, CONTENT);
    Assert.assertEquals(CONTENT + "\n", builder.toString());
    page.exposeBuilderAppendLn(builder, CONTENT);
    Assert.assertEquals(CONTENT + "\n" + CONTENT + "\n", builder.toString());
  }

  @Test(expected = MissingArgumentException.class)
  public void getArgumentTestFail() throws MissingArgumentException, ParseException {
    TestableWebPage page = makeTesTableWebPage();
    page.exposeGetArgument(new HashMap<String, String>(), MAP_KEY);
  }

  @Test
  public void getArgumentTest() throws MissingArgumentException, ParseException {
    TestableWebPage page = makeTesTableWebPage();
    HashMap<String, String> map = new HashMap<String, String>();
    map.put(MAP_KEY, CONTENT);
    Assert.assertEquals(CONTENT, page.exposeGetArgument(map, MAP_KEY));
  }

  @Test
  public void linkTest() throws ParseException {
    TestableWebPage page = makeTesTableWebPage();
    Assert.assertEquals("<a href=\"" + URL_STR + "\">" + CONTENT + "</a>", page.exposeLink(URL_STR,
        CONTENT));
  }

  @Test
  public void constructorTest() throws ParseException {
    TournamentManager manager = new TournamentManager();
    HTTPReq req = makeReq();
    Users users = new Users("");
    TestableWebPage page = new TestableWebPage(manager, req, users);
    Assert.assertSame(manager, page.getManager());
    Assert.assertSame(req, page.getRequest());
    Assert.assertSame(users, page.getUsers());
    Assert.assertFalse(page.isSessionExists());
    Assert.assertNull(page.getSession());
    Assert.assertFalse(page.isRefresh());
    Assert.assertTrue(page.getUrlArgs().isEmpty());
    Assert.assertTrue(page.getPostArgs().isEmpty());
    Assert.assertEquals(1, page.getHeaders().size()); // content-length
    Assert.assertEquals(req.trimmedUrl(), page.getTrimmedURL());
  }

  @Test
  public void constructorWArgsTest() throws ParseException {
    TournamentManager manager = new TournamentManager();
    HTTPReq req = makeReqUrlArgs(ARGS[0] + "=" + VALS[0] + "&" + ARGS[1] + "=" + VALS[1] + "&" + ARGS[2] + "=" + VALS[2]);
    Users users = new Users("");
    TestableWebPage page = new TestableWebPage(manager, req, users);
    Assert.assertSame(manager, page.getManager());
    Assert.assertSame(req, page.getRequest());
    Assert.assertSame(users, page.getUsers());
    Assert.assertFalse(page.isSessionExists());
    Assert.assertNull(page.getSession());
    Assert.assertFalse(page.isRefresh());
    Assert.assertTrue(page.getPostArgs().isEmpty());
    Assert.assertEquals(1, page.getHeaders().size()); //content-length
    Assert.assertEquals(req.trimmedUrl(), page.getTrimmedURL());
    
    //diff from constructorTest
    Assert.assertFalse(page.getUrlArgs().isEmpty());
    Assert.assertEquals(3, page.getUrlArgs().size());
    for (int i = 0; i < ARGS.length; i++) {
      Assert.assertTrue(page.getUrlArgs().containsKey(ARGS[i]));
      Assert.assertEquals(VALS[i], page.getUrlArgs().get(ARGS[i]));
    }
  }

  @Test
  public void constructorWPostArgsTest() throws ParseException {
    TournamentManager manager = new TournamentManager();
    HTTPReq req = makeReqPostArgs(ARGS[0] + "=" + VALS[0] + "&" + ARGS[1] + "=" + VALS[1] + "&" + ARGS[2] + "=" + VALS[2]);
    Users users = new Users("");
    TestableWebPage page = new TestableWebPage(manager, req, users);
    Assert.assertSame(manager, page.getManager());
    Assert.assertSame(req, page.getRequest());
    Assert.assertSame(users, page.getUsers());
    Assert.assertFalse(page.isSessionExists());
    Assert.assertNull(page.getSession());
    Assert.assertFalse(page.isRefresh());
    Assert.assertTrue(page.getUrlArgs().isEmpty());
    Assert.assertEquals(1, page.getHeaders().size()); //content-length
    Assert.assertEquals(req.trimmedUrl(), page.getTrimmedURL());
    
    //diff from constructorTest
    Assert.assertFalse(page.getPostArgs().isEmpty());
    Assert.assertEquals(3, page.getPostArgs().size());
    for (int i = 0; i < ARGS.length; i++) {
      Assert.assertTrue(page.getPostArgs().containsKey(ARGS[i]));
      Assert.assertEquals(VALS[i], page.getPostArgs().get(ARGS[i]));
    }
  }

  @Test
  public void refreshTest() throws ParseException {
    TournamentManager manager = new TournamentManager();
    HTTPReq req = makeReqUrlArgs(TestableWebPage.exposeREFRESH() + "=1");
    Users users = new Users("");
    TestableWebPage page = new TestableWebPage(manager, req, users);
    Assert.assertFalse(page.getUrlArgs().isEmpty());
    Assert.assertEquals(1, page.getUrlArgs().size());
    Assert.assertTrue(page.getUrlArgs().containsKey(TestableWebPage.exposeREFRESH()));
    Assert.assertEquals("1", page.getUrlArgs().get(TestableWebPage.exposeREFRESH()));
  }

  private static class TestableWebPage extends WebPage {

    protected TestableWebPage(TournamentManager manager, HTTPReq request, Users users) {
      super(manager, request, users);
    }

    public TournamentManager getManager() {
      return _manager;
    }

    public HTTPReq getRequest() {
      return _request;
    }

    public Users getUsers() {
      return _users;
    }

    public Map<String, String> getUrlArgs() {
      return _urlArgs;
    }

    public Map<String, String> getPostArgs() {
      return _postArgs;
    }

    public Map<String, String> getHeaders() {
      return _headers;
    }

    public boolean isRefresh() {
      return _refresh;
    }

    public String getTrimmedURL() {
      return _trimmedURL;
    }

    public Session getSession() {
      return _session;
    }

    public boolean isSessionExists() {
      return _sessionExists;
    }

    public static String exposeREFRESH() {
      return REFRESH;
    }

    public void exposeBuilderAppendLn(StringBuilder builder, String content) {
      builderAppendLn(builder, content);
    }

    public String exposeGetArgument(Map<String, String> map, String key)
        throws MissingArgumentException {
      return getArgument(map, key);
    }

    public String exposeLink(String url, String text) {
      return link(url, text);
    }

    @Override
    public HTTPResp getResponse() {
      // TODO Auto-generated method stub
      return null;
    }

  }

}
