package com.udapsoft.waf.system;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.servlet.http.HttpServletRequest;

import kr.co.hsnc.common.base.WAFMessages;
import kr.co.hsnc.common.sql.RowSet;
import kr.co.hsnc.common.sql.WAFConnection;
import kr.co.hsnc.common.sql.WAFConnectionImpl;
import kr.co.hsnc.common.util.StringUtil;
import kr.co.hsnc.common.util.ValueObject;
import kr.co.hsnc.j2ee.components.multipart.MultipartWrapper;
import kr.co.hsnc.j2ee.components.multipart.UploadedFile;
import kr.co.hsnc.j2ee.waf.controller.web.util.WebKeys;
import kr.co.udapsoft.common.menu.MenuManager;

import com.udapsoft.waf.common.web.paging.PageAnchorInfo;

/**
 * HandlerStorage는 Handler로부터 BizClass로 다시 JSP-Layer로 일관된 정보의 접근과 데이터의 교환을 지원한다.
 * 
 * @author DaeJin Lee
 */
public class HandlerStorage {

	/**
	 * HandlerStorage가 Session에 적대될때 사용된다.
	 */
	public final static String KEY = "WAFHandlerStorage";

	/**
	 * Request
	 */
	public HttpServletRequest request = null;

	/**
	 * multi-part/form 데이터를 처리하기 위해 Wrapping된 HttpServletRequest
	 */
	private MultipartWrapper wrapper2 = null;

	/**
	 * DataBase Connection
	 */
	private WAFConnection conn = null;

	/**
	 * 전송된 Request가 multi-part/form Encoding 여부
	 */
	private boolean isMultiPart = false;

	/**
	 * RowSet의 적재 Hashtable
	 */
	private Hashtable<String, RowSet> rowSets = null;

	/**
	 * ValueObject의 적재 Hashtable
	 */
	private Hashtable<String, ValueObject> valueObjects = null;

	/**
	 * 일반 Object의 적재 Hashtable
	 */
	private Hashtable<String, Object> objects = null;

	/**
	 * Paging 처리를 위한 Helper Class
	 */
	private PageAnchorInfo pageAnchorInfo = null;

	/**
	 * 전송받은 Parameter를 적재한 ValueObject
	 */
	private ValueObject params = null;

	/**
	 * 처리요구를 받는 URI
	 */
	private String currentURI = "";

	/**
	 * 처리요구를 받는 URL
	 */
	private StringBuffer currentURL = new StringBuffer();


	/**
	 * 해당 URI에 기본 Event(Handler에서 Event분기구현을 한다.)
	 */
	private String defaultEvent = "";

	/**
	 * Biz Class의 Biz-Logic 처리 성공 여부 비즈객체들에서 에러가 나면 false 를 set 한다
	 */
	private boolean success = true;

	/**
	 * BizClass에서 JSP-Layer로 전달할 Message
	 */
	private String message = "";

	/**
	 * BizClass에서 JSP-Layer로 전달할 상세 Message
	 */
	private String detailMessage = "";

	/**
	 * HandlerStorage의 생성자<br>
	 * HttpServeltRequest의 요청의 의해서 초기화 된다.
	 */
	public HandlerStorage(HttpServletRequest request) {

		this.rowSets = new Hashtable<String, RowSet>();
		this.valueObjects = new Hashtable<String, ValueObject>();
		this.objects = new Hashtable<String, Object>();

		this.request = request;
		this.currentURI = request.getRequestURI();
		this.currentURL = request.getRequestURL();
		this.conn = new WAFConnectionImpl();

		if (request instanceof MultipartWrapper) {
			isMultiPart = true;
		}

		ParameterParser parameterParser = new ParameterParser(request);
		params = parameterParser.getParams();
	}

	/**
	 * HandlerStorage의 생성자<br>
	 */
	public HandlerStorage() {
		this.rowSets = new Hashtable<String, RowSet>();
		this.valueObjects = new Hashtable<String, ValueObject>();
		this.objects = new Hashtable<String, Object>();
		this.conn = new WAFConnectionImpl();
		this.params = new ValueObject();
	}

	/**
	 * HandlerStorage의 생성자<br>
	 * ValueObject params만 받는다.
	 */
	public HandlerStorage(ValueObject params) {
		this.rowSets = new Hashtable<String, RowSet>();
		this.valueObjects = new Hashtable<String, ValueObject>();
		this.objects = new Hashtable<String, Object>();
		this.conn = new WAFConnectionImpl();
		this.params = params.copy();
	}

	/**
	 * HandlerStorage의 생성자<br>
	 * ValueObject params, WAFConnection conn만 받는다.
	 */
	public HandlerStorage(ValueObject params, WAFConnection conn) {
		this.rowSets = new Hashtable<String, RowSet>();
		this.valueObjects = new Hashtable<String, ValueObject>();
		this.objects = new Hashtable<String, Object>();
		this.conn = conn;
		this.params = params.copy();
	}

	/**
	 * JDBC Connection을 리턴한다.
	 * 
	 * @return
	 */
	public WAFConnection getWAFConnection() {
		return this.conn;
	}

	/**
	 * Biz Class의 Biz-Logic 처리 성공 여부를 세팅한다.
	 * 
	 * @param success
	 */
	public void setSuccess(boolean success) {
		this.success = success;
	}

	/**
	 * Biz Class의 Biz-Logic 처리 성공 여부 리턴한다.
	 * 
	 * @return
	 */
	public boolean getSuccess() {
		return this.success;
	}

	/**
	 * Message를 세팅한다.
	 * 
	 * @param message
	 */
	public void setMessage(String message) {
		this.message = message;
	}

	/**
	 * Message를 리턴한다.
	 * 
	 * @return
	 */
	public String getMessage() {
		String temp = this.message;
		temp = StringUtil.replace(temp, "\n", "\\n");
		temp = StringUtil.replace(temp, "\"", "'");
		return temp;
	}

	/**
	 * 상세 Message를 세팅한다.
	 * 
	 * @param detailMessage
	 */
	public void setDetailMessage(String detailMessage) {
		this.detailMessage = detailMessage;
	}

	/**
	 * 상세메세지의 Exception의 StackTrace를 세팅한다.
	 * 
	 * @param e
	 */
	public void setDetailMessage(Exception exception) {
		StringWriter stringWriter = new StringWriter();
		exception.printStackTrace(new PrintWriter(stringWriter));
		this.detailMessage = stringWriter.toString();
	}

	/**
	 * 상세 Message를 리턴한다.
	 * 
	 * @return
	 */
	public String getDetailMessage() {
		String temp = this.detailMessage;
		// temp = StringUtil.replace(temp, "\"", "'");
		// temp = StringUtil.replace(temp, "\r", "\\r");
		// temp = StringUtil.replace(temp, "\n", "\\n");
		return temp;
	}

	/**
	 * 전송된 Request가 multi-part/form Encoding 여부를 리턴한다.
	 * 
	 * @return
	 */
	public boolean isMultiPart() {

		return this.isMultiPart;
	}

	/**
	 * 전송된 Request를 리턴한다.
	 * 
	 * @return
	 */
	public HttpServletRequest getRequest() {

		return this.request;
	}

	/**
	 * multi-part/form 데이터를 처리하기 위해 Wrapping된 HttpServletRequest를 리턴한다.
	 * 
	 * @return
	 */
	public MultipartWrapper getMultipartWrapper() {

		return (MultipartWrapper) request;
	}

	/**
	 * 첨부파일의 원본 이름을 리턴한다.
	 * 
	 * @param key
	 * @return
	 */
	public String getOriginalFileName(String key) {
		if (this.isMultiPart)
			return ((MultipartWrapper) request).getOriginalFileName(key);
		return null;
	}

	/**
	 * 첨부파일의 Content Type 을 리턴한다.
	 * 
	 * @param key
	 * @return
	 */
	public String getContentType(String key) {
		if (this.isMultiPart)
			return ((MultipartWrapper) request).getContentType(key);
		return null;
	}

	/**
	 * 첨부파일의 File 객체를 리턴한다.
	 * 
	 * @param key
	 * @return
	 */
	public java.io.File getFile(String key) {
		if (this.isMultiPart)
			return ((MultipartWrapper) request).getFile(key);
		return null;
	}

	/**
	 * @return
	 */
	public Enumeration<?> getFileKeys() {
		if (this.isMultiPart)
			return ((MultipartWrapper) request).getFileNames();
		return null;
	}

	/**
	 * 첨부파일의 File 객체를 리턴한다.
	 * 
	 * @param key
	 * @return
	 */
	public UploadedFile[] getUploadedFiles(String key) {
		if (this.isMultiPart)
			return ((MultipartWrapper) request).getUploadFiles(key);
		return null;
	}

	/**
	 * 기본 Event를 세팅한다.
	 * 
	 * @param defaultEvent
	 */
	public void setDefaultEvent(String defaultEvent) {

		this.defaultEvent = defaultEvent;
	}

	/**
	 * 현재 처리중인 URI를 리턴한다.
	 * 
	 * @return
	 */
	public String getCurrentURI() {
		return currentURI;
	}
	
	public StringBuffer getCurrentURL() {
		return currentURL;
	}

	/**
	 * 현재 처리중인 서버 URL을 리턴한다.
	 * 
	 * @return
	 */
	public String getCurrentDoamin() {
		return request.getScheme() + "://" + request.getServerName() + ":"
				+ request.getServerPort() + "/" + request.getContextPath();
	}

	/**
	 * SCREEN NAME을 리턴한다.
	 * 
	 * @return
	 */
	public String getScreenName() {
		String screenName = currentURI;
		if (screenName.lastIndexOf("/") > 0) {
			screenName = screenName.substring(screenName.lastIndexOf("/") + 1, screenName.length());
		}

		return screenName;
	}

	/**
	 * Array로 전송된 Parameter를 리턴한다.
	 * 
	 * @param key
	 * @return
	 */
	public String[] gets(String key) {

		String[] values = null;

		if (!isMultiPart)
			values = this.request.getParameterValues(key);
		else
			values = this.wrapper2.getParameterValues(key);

		if (values == null) {
			values = new String[0];
		}

		// return values;
		if (this.params.getObject(key) instanceof String[]) {
			return (String[]) this.params.getObject(key);
		} else {
			if (this.params.containsKey(key)) {
				String[] value = new String[1];
				value[0] = this.params.get(key);
				return value;
			} else {
				String[] value = new String[0];
				return value;
			}
		}
	}

	/**
	 * 전송된 Parameter를 리턴한다.(값을 없는 경우에는 넘겨받은 기본값을 리턴한다.)
	 * 
	 * @param key
	 * @param defaultValue
	 * @return
	 */
	public String get(String key, String defaultValue) {

		String value = get(key);

		if (value.equals("")) {
			value = defaultValue;
		}
		return value;
	}

	/**
	 * 전송된 Parameter를 리턴한다.
	 * 
	 * @param key
	 * @return
	 */
	public String get(String key) {

		String value = null;

		if (!isMultiPart)
			value = this.request.getParameter(key);
		else
			value = this.wrapper2.getParameter(key);

		if (value == null) {
			value = "";
		}
		return value;
	}

	/**
	 * 현재 처리중인 Event와 입력받은 Event와 비교해서 true/false를 리턴한다.(대소문자 구분 없음)
	 * 
	 * @param event
	 * @return
	 */
	public boolean compareEvent(String event) {

		return getEvent().equalsIgnoreCase(event);
	}

	/**
	 * 현재 처리중인 Event를 리턴한다.
	 * 
	 * @return
	 */
	public String getEvent() {
		if (params != null)
			return params.get("fevent", this.defaultEvent);
		return "";
	}

	/**
	 * RowSet의 적재 Hashtable의 길이를 리턴한다.
	 * 
	 * @return
	 */
	public int getRowSetSize() {

		return rowSets.size();
	}

	/**
	 * RowSet의 적재 Hashtable에서 Key에 해당하는 RowSet을 리턴한다.
	 * 
	 * @param key
	 * @return
	 */
	public RowSet getRowSet(String key) {

		return (RowSet) rowSets.get(key);
	}

	/**
	 * RowSet을 적재한다.
	 * 
	 * @param key
	 * @param rowSet
	 */
	public void addRowSet(String key, RowSet rowSet) {

		rowSets.put(key, rowSet);
	}

	/**
	 * RowSet의 적재 Hashtable에서 key에 해당하는 RowSet을 제거한다.
	 * 
	 * @param key
	 */
	public void removeRowSet(String key) {

		rowSets.remove(key);
	}

	/**
	 * RowSet의 적재 Hashtable을 Clear한다.
	 * 
	 * @see java.util.Hashtable#clear()
	 */
	public void clearRowSet() {

		rowSets.clear();
	}

	/**
	 * ValueObject의 적재 Hashtable의 길이를 리턴한다.
	 * 
	 * @return
	 */
	public int getValueObjectSize() {

		return valueObjects.size();
	}

	/**
	 * ValueObject의 적재 Hashtable에서 key에 해당하는 ValueObject를 리턴한다.
	 * 
	 * @param key
	 * @return
	 */
	public ValueObject getValueObject(String key) {

		return (ValueObject) valueObjects.get(key);
	}

	/**
	 * ValueObject의 적재 Hashtable에 ValueObject를 적재한다.
	 * 
	 * @param key
	 * @param valueObject
	 */
	public void addValueObject(String key, ValueObject valueObject) {

		valueObjects.put(key, valueObject);
	}

	/**
	 * ValueObject의 적재 Hashtable에서 key에 해당하는 ValueObject를 제거한다.
	 * 
	 * @param key
	 */
	public void removeValueObject(String key) {

		valueObjects.remove(key);
	}

	/**
	 * ValueObject의 적재 Hashtable을 Clear한다.
	 * 
	 * @see java.util.Hashtable#clear()
	 */
	public void clearValueObject() {

		valueObjects.clear();
	}

	/**
	 * Object의 적재 Hashtable의 길이를 리턴한다.
	 * 
	 * @return
	 */
	public int getObjectSize() {

		return objects.size();
	}

	/**
	 * Object의 적재 Hashtable에서 key에 해당하는 Object를 리턴한다.
	 * 
	 * @see java.util.Hashtable#get()
	 * @param key
	 * @return
	 */
	public Object getObject(String key) {

		return (Object) objects.get(key);
	}
	
	public Hashtable<String, Object> getObjectList() {
		return this.objects;
	}

	/**
	 * Object의 적재 Hashtable에 Object를 적재한다.
	 * 
	 * @param key
	 * @param valueObject
	 */
	public void addObject(String key, Object valueObject) {

		objects.put(key, valueObject);
	}

	/**
	 * Object의 적재 Hashtable에서 key에 해당하는 ValueObject를 제거한다.
	 * 
	 * @param key
	 */
	public void removeObject(String key) {

		objects.remove(key);
	}

	/**
	 * Object의 적재 Hashtable을 Clear한다.
	 * 
	 * @see java.util.Hashtable#clear()
	 * @param key
	 */
	public void clearObject() {

		objects.clear();
	}

	/**
	 * Paging 처리를 위한 Helper Class를 생성한다.
	 */
	public void createPageAnchorInfo() {
		this.pageAnchorInfo = new PageAnchorInfo(this.request);
	}

	/**
	 * Paging 처리를 위한 Helper Class를 세팅한다.
	 * 
	 * @param pageAnchorInfo
	 */
	public void setPageAnchorInfo(PageAnchorInfo pageAnchorInfo) {
		this.pageAnchorInfo = pageAnchorInfo;
	}

	/**
	 * Paging 처리를 위한 Helper Class를 리턴한다.
	 * 
	 * @return
	 */
	public PageAnchorInfo getPageAnchorInfo() {
		return this.pageAnchorInfo;
	}

	/**
	 * 전송받은 Parameter를 적재한 ValueObject를 입력한 ValueObject로 대체한다.
	 * 
	 * @param params
	 */
	public void setParams(ValueObject params) {

		this.params = params;
	}

	/**
	 * 전송받은 Parameter를 적재한 ValueObject를 리턴한다.
	 * 
	 * @return
	 */
	public ValueObject getParams() {

		return this.params;
	}

	/**
	 * 사용자 정보를 리턴
	 * 
	 * @return
	 */
	public ValueObject getUser() {
		return (ValueObject) this.request.getSession().getAttribute(
				WebKeys.SIGNED_ON_USER);
	}

	/**
	 * @param user
	 */
	public void setUser(ValueObject user) {
		this.request.getSession().setAttribute(WebKeys.SIGNED_ON_USER, user);
	}

	/**
	 * SignOn된 사용자의 Global 변수에 IN_DEPT_CD SQL 변경
	 * 
	 * @param sqlStr
	 */
	public void setUserInDeptCD(String sqlStr) {
		ValueObject user = null;
		user = this.getUser();
		user.set("IN_DEPT_CD_SQL", sqlStr);
		this.setUser(user);
	}

	/**
	 * 프로그램 목록에 등록되어 있는 프로그램명을 리턴한다.
	 * 
	 * @return
	 */
	public String getPgmName() {
		return MenuManager.getPgmName(getCurrentURI());
	}

	/**
	 * WAFMessages를 통해 Message를 리턴한다.
	 * 
	 * @param key
	 * @return
	 * @see com.evali.common.base.WAFMessages#getMessage()
	 */
	public String getWAFMessage(String key) {
		return WAFMessages.getMessage(key);
	}

	/**
	 * HandlerStorage에 message필드를 전달받은 key를 통해 WAFMessage와 bind시킨다.
	 * 
	 * @param key
	 * @see com.evali.common.base.WAFMessages#getMessage()
	 */
	public void bindWAFMessage(String key) {
		this.message = getWAFMessage(key);
	}

	public String toString() {
		return this.params.toString();
	}
}
