/*
 * Paraselene
 * Copyright (c) 2009  Akira Terasaki
 * このファイルは同梱されているLicense.txtに定めた条件に同意できる場合にのみ
 * 利用可能です。
 */
package paraselene.supervisor;


import paraselene.*;
import java.util.*;
import java.net.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;


class DataHolder {
	Supervisor	sv;
	RequestParameter	request;
	HttpServletRequest	req;
	HttpServletResponse	response;
	SessionData	data;
	PageID	myself = null;
	boolean	history_use = false;
	boolean	session_null = true;
	boolean search_engine = false;

	DataHolder( Supervisor s ) { sv = s; }
}

class RedirectData implements Serializable {
	private static final long serialVersionUID = 2L;
	String	uri;
	Forward	fw;
	Page[]	out_page;
}

class SessionData implements Serializable {
	private static final long serialVersionUID = 2L;
	TransactionSequencer seq = new TransactionSequencer();
	HistorySet hist = new HistorySet();
	private HashMap<PageID, RedirectData>	pending = new HashMap<PageID, RedirectData>();
	private volatile int client;

	private int getClient( HttpServletRequest req ) {
		String[]	data = new String[] {
			req.getHeader( RequestParameter.UA_HEAD ),
			req.getHeader( "HTTP-Client-IP" ),
			req.getHeader( "X-Forwarded-For" ),
			req.getHeader( "Remote-Addr" )
		};
		StringBuilder	buf = new StringBuilder();
		for ( int i = 0; i < data.length; i++ ) {
			if ( data[i] == null )	data[i] = "non";
			buf = buf.append( "*" );
			buf = buf.append( data[i] );
		}
		return buf.toString().hashCode();
	}

	SessionData( HttpServletRequest req ) {
		client = getClient( req );
	}

	boolean isSame( HttpServletRequest req ) {
		if ( client == getClient( req ) )	return true;
		client = 0;
		System.out.println( "unmatched client" );
		return false;
	}

	boolean write( Supervisor sv, Page out, DataHolder holder ) throws Exception {
		PageID	id = out.getID();
		RedirectData	data = null;
		synchronized( pending ) {
			data = pending.get( id );
		}
		id.getPageFactory().returnPage( out );
		if ( data == null )	return false;
		if ( holder.request.getURI().toString().indexOf( data.uri ) < 0 )	return false;
		sv.write( data.out_page, false, data.fw, holder );
		return true;
	}

	Forward redirect( Page[] out_ret, Forward fw, DataHolder holder ) throws Exception {
		RedirectData	rd = new RedirectData();
		rd.fw = fw;
		rd.out_page = out_ret;
		URI	uri = holder.request.getURI();
		rd.uri = TransactionSequencer.makeRedirectURI( seq, out_ret[0].getID() );
		String	path = URIValue.makeAbsolutePath(
			URIValue.Scheme.getScheme( uri ), uri.getPort(), rd.uri
		);
		synchronized( pending ) {
			pending.put( out_ret[0].getID(), rd );
		}
		return new Forward( new URI( path ), false );
	}
}



