package org.japanosample.test;

import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.HTMLElement;
import com.meterware.httpunit.HttpInternalErrorException;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebResponse;
import com.meterware.servletunit.ServletRunner;
import com.meterware.servletunit.ServletUnitClient;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.xerces.xni.XNIException;
import org.japano.Servlet;
import org.xml.sax.SAXException;

/**
 Tests the japano sample application via httpunit 
  
 @author  Sven Helmberger ( sven dot helmberger at gmx dot de )
 @version $Id: TestJapanoSample.java,v 1.6 2005/08/17 23:46:22 fforw Exp $
 */
public class TestJapanoSample
{
  private static org.apache.log4j.Logger logger=org.apache.log4j.Logger.getLogger( TestJapanoSample.class);
  
  private ServletUnitClient sc;
    
  public static void main( String[] args) throws Exception
  {
    if (args.length == 0)
      args=new String[] { "/home/sven/src/sf/japano/sample/webapp/WEB-INF/web.xml" };
    new TestJapanoSample().main(args[0]);
  }
  
  private void main(String webxml) throws Exception
  {
    File webXML=new File( webxml);
    //System.out.println("webXML:"+webXML);
    ServletRunner sr = null;
    
    Hashtable initParameters=new Hashtable();
    initParameters.put("sessionClass", "org.japanosample.SampleSession");
    initParameters.put("welcomeView", "/index.jsp");
    initParameters.put("compilePages", "true");
    
    try
    {
      sr=new ServletRunner( webXML, "" );
      sr.registerServlet( "*.jsp", Servlet.class.getName(), initParameters);      
      sc = sr.newClient();
      String url="http://127.0.0.1/";  
      WebResponse response=sc.getResponse( new GetMethodWebRequest( url ));      
      String sessionId=sc.getCookieValue(Servlet.JPNID_PARAM);
      
      if (sessionId.length() != 16)
        throw new IllegalStateException("session id is not 16 characters long.");
      
//      System.out.println("URL : "+response.getURL());         
//      System.out.println("session id : "+sessionId);         
      
      // check if index link links to the first URL
      WebResponse curResponse=response.getLinkWithID("nlIndex").click();
      if (!response.getURL().equals( curResponse.getURL()))
        throw new IllegalStateException("index via navmenu leads to another URL: "+response.getURL()+" != "+curResponse.getURL());
     
      curResponse=testRepeat(curResponse);
      curResponse=testCalc(curResponse);
      curResponse=testUser(curResponse);
      
      testError(sc);
    }
    finally
    {
      if (sr != null)
        sr.shutDown();
    }    
  }
  
  private void testError(ServletUnitClient sc) throws MalformedURLException, IOException, SAXException
  {      
    WebResponse curResponse=sc.getResponse( new GetMethodWebRequest( "http://127.0.0.1/test/ntThrow.jsp"));      
    if (!Pattern.matches(".*NO-ERROR.*", curResponse.getText()))
      throw new RuntimeException("NO-ERROR not found");

    System.out.println("The following error is done on purpose and is no test error:");
    try
    {
      GetMethodWebRequest webRequest=new GetMethodWebRequest( "http://127.0.0.1/test/ntThrow.jsp");
      webRequest.setParameter("error", "1");
      curResponse=sc.getResponse( webRequest);      
    }
    catch (HttpInternalErrorException e)
    {
      if (e.getResponseCode() != 500)
        throw new RuntimeException("expected error-code 500");      
      System.out.println("testError() OK.");
      return;
    }
    throw new RuntimeException("error failed.");
  }
  
  private WebResponse testRepeat(WebResponse curResponse) throws Exception
  {
    curResponse=curResponse.getLinkWithID("nlRepeat").click();
    String text=curResponse.getText();
    if (!Pattern.matches(".*Repetition[ ]+0.*Repetition[ ]+1.*Repetition[ ]+2.*Repetition[ ]+3.*Repetition[ ]+4.*", text))
      throw new IllegalStateException("Repeat page regex failed for "+text);
    System.out.println("testRepeat() OK.");
    return curResponse;
  }

  private WebResponse testCalc(WebResponse curResponse) throws Exception
  {
    curResponse=curResponse.getLinkWithID("nlCalc").click();    
    // we start with 0
    checkNumber(curResponse, 0);
    curResponse=curResponse.getLinkWithID("minus2").click();
    // -2 = -2
    checkNumber(curResponse, -2);
    curResponse=sc.getResponse( curResponse.getURL().toExternalForm());
    // reloading the substract action should not change the value
    checkNumber(curResponse, -2);
    // +1 = -1 
    curResponse=curResponse.getLinkWithID("plus1").click();
    checkNumber(curResponse, -1);
    // reloading the add action should change the value to 0
    curResponse=sc.getResponse( curResponse.getURL().toExternalForm());
    checkNumber(curResponse, 0);
    
    System.out.println("testCalc() OK.");
    
    return curResponse;
  }
  
  private WebResponse testUser(WebResponse curResponse) throws Exception
  {
    curResponse=curResponse.getLinkWithID("nlLogin").click();    
    
    WebForm login=getForm(curResponse, "formLogin");
    login.setParameter( "EMail", "user@example.org");
    login.setParameter( "password", "password");
    curResponse=login.submit();
    
    final String ILLEGAL_EMAIL="illegal#example.org";
    final String LEGAL_EMAIL="legal@example.org";
    
    // try invalid email
    WebForm edit=getForm(curResponse, "formEdit");
    edit.setParameter( "user.EMail", ILLEGAL_EMAIL);
    curResponse=edit.submit();

    HTMLElement[] elements=curResponse.getElementsWithAttribute("class", "fieldError");
    if (elements.length != 1 || !elements[0].getAttribute("value").equals(ILLEGAL_EMAIL))
      throw new RuntimeException("Illegal email address not recognized.");
    
    edit=getForm(curResponse, "formEdit");
    edit.setParameter( "user.EMail", LEGAL_EMAIL);
    curResponse=edit.submit();

    elements=curResponse.getElementsWithAttribute("class", "fieldError");
    if (elements.length > 0)
      throw new RuntimeException("Legal email caused fieldError: "+curResponse.getText());
    
    edit=getForm(curResponse, "formEdit");
    String value=edit.getParameterValue("user.EMail");
    if (!value.equals(LEGAL_EMAIL))
      throw new RuntimeException("value is \""+value+"\" not \""+LEGAL_EMAIL+"\"");
      
    System.out.println("testUser() OK.");
    
    return curResponse;
  }
  
  private WebForm getForm(WebResponse response, String id) throws SAXException
  {
    WebForm form=response.getFormWithID(id);
    if (form == null)
      throw new RuntimeException("No form with id \""+id+"\"");
    return form;
  }

  private void checkNumber(WebResponse curResponse, int expected) throws Exception
  {
    Pattern p=Pattern.compile(".*\\QNumber: \\E(\\-?[0-9]+).*");
    String text=curResponse.getText();
    Matcher m=p.matcher( text);
    if (!m.matches())
    {
      throw new IllegalStateException("Regex did not match "+text);
    }
    
    int number=Integer.parseInt( m.group(1));
    if (number != expected)
      throw new IllegalStateException("Number mismatch. expected: "+expected+", is: "+number);
  }  
}