/*  OpenOlap viewer
 *  パッケージ名：openolap.viewer
 *  ファイル：Report.java
 *  説明：レポートをあらわすクラスです。
 *
 *  作成日: 2003/12/29
 */

package openolap.viewer;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeMap;

import openolap.viewer.common.Constants;
import openolap.viewer.common.Messages;
import openolap.viewer.controller.RequestHelper;
import openolap.viewer.dao.DAOFactory;
import openolap.viewer.dao.DimensionMemberDAO;
import openolap.viewer.dao.ReportDAO;

/**
 *  クラス：Report
 *  説明：レポートをあらわすクラスです。
 */
public class Report implements Serializable {

	// ********** インスタンス変数 **********

	/** レポート名 */
	private String reportName = null;

	/** レポートID */
	final private String reportID;

	/** 親ID(レポートを格納するフォルダのID) */
	private String parentID;

	/** キューブ */
	final private Cube cube;

	/** エッジをあらわすオブジェクトリスト */
	final private ArrayList edgeList;

	/** 色をあらわすオブジェクトのリスト */
	final private ArrayList colorList;

	/** 時間次元を持つか */
	final private boolean hasTimeDim;

	/** 新規作成中で未保存のレポート(true)か、既存レポート(false)か */
	private boolean isNewReport = false;

	// ********** コンストラクタ **********

	/**
	 * レポートオブジェクトを生成します。
	 */
	public Report(String reportID, String reportName, Cube cube, ArrayList edgeList, ArrayList colorList, boolean hasTimeDim){
		this.reportID = reportID;
		this.reportName = reportName;
		this.parentID = null;
		this.cube = cube;
		this.edgeList = edgeList;
		this.colorList = colorList;
		this.hasTimeDim = hasTimeDim;
	}


	// ********** 静的メソッド **********

	/**
	 * 時間軸を持つ場合true、持たない場合falseを戻す。
	 * @param edgeList 軸リスト
	 */
	public static boolean investigateTimeDimension(ArrayList edgeList) {
		Edge col = (Edge)Edge.getTheEdge("COL",edgeList);
		Edge row = (Edge)Edge.getTheEdge("ROW",edgeList);
		Edge page = (Edge)Edge.getTheEdge("PAGE",edgeList);

		return (col.investigateTimeDimension() || row.investigateTimeDimension() || page.investigateTimeDimension());
	}

	/**
	 * 与えられたディメンションリスト、メジャーリストを配置したエッジをあらわすオブジェクトのリストを戻す。
	 * @param dimList ディメンションをあらわすオブジェクトのリスト
	 * @param measure メジャーをあらわすオブジェクト
	 * @return エッジをあらわすオブジェクトのリスト
	 */
	public static ArrayList initializeEdge(ArrayList dimList, Measure measure) {
		if ( (dimList == null) || (measure == null) ) { throw new IllegalArgumentException(); }
		if (dimList.size() < 1) { throw new IllegalArgumentException(); }

		Col col = null;
		Row row = null;
		Page page = null;
		ArrayList pageAxisList = new ArrayList();

		dimList.add(measure);

		col = new Col((Axis)dimList.get(0));
		row = new Row((Axis)dimList.get(1));

		if ( dimList.size()-2 > 0 ) { // ディメンションをふたつ以上持つ（ページエッジが軸を持つ）場合
			for(int i=0; i<(dimList.size()-2); i++){
				pageAxisList.add(dimList.get(i+2));
				page = new Page(pageAxisList);
			}
		} else {	// ページエッジに軸が存在しない場合、空のArrayListを持たせる
			page = new Page(new ArrayList());
		}

		ArrayList edgeList = new ArrayList();
		edgeList.add(col);
		edgeList.add(row);
		edgeList.add(page);

		return edgeList;
	}

	public static String getInitialReportName() {
		return Messages.getString("Report.tempInitialReportName"); //$NON-NLS-1$
	}

	// ********** メソッド **********

	/**
	 * Reportオブジェクトの行、列エッジに配置されたディメンションに、軸メンバーオブジェクトをセットする
	 * @param helper RequestHelperをあらわすオブジェクトのリスト
	 * @param report レポートをあらわすオブジェクト
	 * @param conn コネクションをあらわすオブジェクト
	 */
	public void setSelectedCOLROWDimensionMembers(RequestHelper helper, Report report, Connection conn) throws SQLException {

		DimensionMemberDAO dimMemberDAO = DAOFactory.getDAOFactory().getDimensionMemberDAO(conn);

		Iterator it = report.getEdgeList().iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			Iterator it2 = edge.getAxisList().iterator();

			if (edge.getPosition().equals(Constants.Page)) {
				continue;
			}

			int i = 0;
			while (it2.hasNext()) {
				Axis axis = (Axis) it2.next();
				Dimension dim = null;
				if(axis instanceof Dimension) {
					dim = (Dimension) axis;
				} else {
					i++;
					continue;
				}

				String selectedMemberList = "";
				if (edge.getPosition().equals(Constants.Col)) {
					selectedMemberList = "'," + helper.getRequest().getSession().getAttribute("viewCol" + i + "KeyList_hidden") + ",'";
				} else if (edge.getPosition().equals(Constants.Row)) {
					selectedMemberList = "'," + helper.getRequest().getSession().getAttribute("viewRow" + i + "KeyList_hidden") + ",'";
				}

				ArrayList dimMemberList = dimMemberDAO.selectDimensionMembers(dim, null, null, null, selectedMemberList);
				dim.clearAxisMember();
				dim.addAllAxisMember(dimMemberList);

				i++;
			}
		}
	}


	/**
	 * レポートのディメンションオブジェクトが持つメンバーを削除する
	 */
	public void clearDimensionMembers() {

		Iterator it = edgeList.iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			Iterator it2 = edge.getAxisList().iterator();
			while (it2.hasNext()) {
				Axis axis = (Axis) it2.next();
				if(!axis.isMeasure()){
					axis.clearAxisMember();
				}
			}
		}
	}


	/**
	 * レポートの持つ総ディメンション数を求める。
	 * @return 総ディメンション数
	 */
	public int getTotalDimensionNumber(){

		Iterator it = edgeList.iterator();
		int dimCounter = 0;
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			Iterator it2 = edge.getAxisList().iterator();
			while (it2.hasNext()) {
				Axis axis = (Axis) it2.next();
				if(!axis.isMeasure()){
					dimCounter++;
				}
			}
		}

		return dimCounter;
	}

	/**
	 * レポートの持つ総メジャーメンバー数を求める。
	 * @return 総メジャーメンバー数
	 */
	public int getTotalMeasureMemberNumber(){
		ArrayList measureMemberList = this.getMeasure().getAxisMemberList();
		return measureMemberList.size();
	}

	/**
	 * 与えられた名称のエッジオブジェクトを求める。
	 * @param edgeType エッジをあらわす名称（COL,ROW,PAGE）
	 * @return エッジオブジェクト
	 */
	public Edge getEdgeByType(String edgeType) {
		Iterator it = edgeList.iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			if (edge.getPosition().equals(edgeType)){
				return edge;
			}
		}
		return null;
	}

	/**
	 * メジャーオブジェクトを求める。
	 * @return メジャーオブジェクト
	 */
	public Measure getMeasure() {
		Iterator it = this.getEdgeList().iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			if(edge.getMeasure() != null) {
				return edge.getMeasure();
			}
		}
		throw new IllegalStateException();
	}

	/**
	 * 与えられたIDの軸オブジェクトを求める。
	 * 軸オブジェクトが存在しない場合はnullを戻す。
	 * @return 軸オブジェクト
	 */
	public Axis getAxisByID(String sourceID) {
		Iterator it = this.getEdgeList().iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			Iterator axisIt = edge.getAxisList().iterator();

			while (axisIt.hasNext()) {
				Axis axis = (Axis) axisIt.next();

				if(axis.getId().equals(sourceID)) {
					return axis;
				}
			}
		}
		return null;
	}

	/**
	 * AxisId の昇順で軸オブジェクトを取得する。
	 * @return 軸オブジェクトのリスト
	 */
	public ArrayList getAxilOrderByID() {
		ArrayList axisList = new ArrayList();

		TreeMap axisIdObjMap = new TreeMap();
		Iterator it = this.getEdgeList().iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			Iterator axisIt = edge.getAxisList().iterator();

			while (axisIt.hasNext()) {
				Axis axis = (Axis) axisIt.next();
				axisIdObjMap.put(Integer.decode(axis.getId()), axis);
			}
		}

		Iterator axisIt = axisIdObjMap.keySet().iterator();
		while (axisIt.hasNext()) {
			Integer axisID = (Integer) axisIt.next();
			Axis axis = (Axis) axisIdObjMap.get(axisID) ;
			axisList.add(axis);
		}

		return axisList;
	}

	/**
	 * 与えられた軸が配置されているエッジの名称を求める。
	 * 軸オブジェクトが存在しない場合はnullを戻す。
	 * @param oAxis 軸をあらわすオブジェクト
	 * @return エッジの名称
	 */
	public String getThisAxisPosition(Axis oAxis) {
		if (oAxis == null){ return null; }
		Iterator it = this.getEdgeList().iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			if (edge.hasThisAxis(oAxis)){
				return edge.getPosition();
			}
		}
		return null;
	}

	/**
	 * 与えられた軸が配置されているエッジの名称を求める。
	 * 軸オブジェクトが存在しない場合はnullを戻す。
	 * @param id 軸ID
	 * @return エッジの名称
	 */
	public String getThisAxisPosition(String id) {
		if (id == null){ return null; }
		Iterator it = this.getEdgeList().iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			if (edge.hasThisAxis(id)){
				return edge.getPosition();
			}
		}
		return null;
	}

	/**
	 * 与えられた軸が列エッジに配置されている場合はtrue、配置されていない場合はfalseを戻す。
	 * @param oAxis 軸オブジェクト
	 * @return 列エッジに配置されているか
	 */
	public boolean isInCol(Axis oAxis) {
		if (oAxis == null){ return false; }
		if (this.getThisAxisPosition(oAxis).equals(Constants.Col)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 与えられた軸が列エッジに配置されている場合はtrue、配置されていない場合はfalseを戻す。
	 * @param axisId 軸ID
	 * @return 列エッジに配置されているか
	 */
	public boolean isInCol(String axisId) {
		if (axisId == null){ return false; }
		if (this.getThisAxisPosition(axisId).equals(Constants.Col)) {
			return true;
		} else {
			return false;
		}
	}


	/**
	 * 与えられた軸が行エッジに配置されている場合はtrue、配置されていない場合はfalseを戻す。
	 * @param oAxis 軸オブジェクト
	 * @return 行エッジに配置されているか
	 */
	public boolean isInRow(Axis oAxis) {
		if (oAxis == null){ return false; }
		if (this.getThisAxisPosition(oAxis).equals(Constants.Row)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 与えられた軸が行エッジに配置されている場合はtrue、配置されていない場合はfalseを戻す。
	 * @param axisId 軸ID
	 * @return 行エッジに配置されているか
	 */
	public boolean isInRow(String axisId) {
		if (axisId == null){ return false; }
		if (this.getThisAxisPosition(axisId).equals(Constants.Row)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 与えられた軸がページエッジに配置されている場合はtrue、配置されていない場合はfalseを戻す。
	 * @param oAxis 軸オブジェクト
	 * @return ページエッジに配置されているか
	 */
	public boolean isInPage(Axis oAxis) {
		if (oAxis == null){ return false; }
		if (this.getThisAxisPosition(oAxis).equals(Constants.Page)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 与えられた軸がページエッジに配置されている場合はtrue、配置されていない場合はfalseを戻す。
	 * @param axisId 軸ID
	 * @return ページエッジに配置されているか
	 */
	public boolean isInPage(String axisId) {
		if (axisId == null){ return false; }
		if (this.getThisAxisPosition(axisId).equals(Constants.Page)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 与えられた軸が配置されているエッジ内での段インデックスを求める。
	 * インデックスは「0」startの値である。
	 * 引数としてnullが渡ってきた場合は「-1」を戻す。
	 * 与えられた軸が存在しない場合は「0」を戻す。
	 * @param oAxis 軸オブジェクト
	 * @return エッジ内での段インデックス
	 */
	public int getHieIndex(Axis oAxis) {
		if (oAxis == null){ return -1; }
		Iterator it = this.getEdgeList().iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			if (edge.getAxisIndexInEdge(oAxis) != -1) {
				return edge.getAxisIndexInEdge(oAxis);
			}
		}
		return 0;
	}

	/**
	 * 与えられた軸が配置されているエッジ内での段インデックスを求める。
	 * インデックスは「0」startの値である。
	 * 引数としてnullが渡ってきた場合は「-1」を戻す。
	 * 与えられた軸が存在しない場合は「-1」を戻す。
	 * @param axisID 軸ID
	 * @return エッジ内での段インデックス
	 */
	public int getHieIndex(String axisID) {
		if (axisID == null){ return -1; }
		Iterator it = this.getEdgeList().iterator();
		while (it.hasNext()) {
			Edge edge = (Edge) it.next();
			if (edge.getAxisIndexInEdge(axisID) != -1) {
				return edge.getAxisIndexInEdge(axisID);
			}
		}
		return -1;
	}

	/**
	 * 指定されたエッジに配置された軸メンバーの組み合わせ数を求める。
	 * @param edgeName 軸名称
	 * @return メンバーの組み合わせ数
	 */
	public int getAxisMeberComboNum(String edgeName) {
		if ( (!Constants.Col.equals(edgeName)) && (!Constants.Row.equals(edgeName)) && (!Constants.Page.equals(edgeName)) ) {
			throw new IllegalStateException();
		}

		int totalNumber = 1;
		ArrayList edgeAxesList = this.getEdgeByType(Constants.Col).getAxisList();
		Iterator iter = edgeAxesList.iterator();
		while (iter.hasNext()) {
			Axis axis = (Axis) iter.next();
			totalNumber = totalNumber * (axis.getAxisMemberList().size());
		} 

		return totalNumber;
	}

	/**
	 * 色を表すオブジェクトをレポートに追加する。
	 * @param color 色をあらわすオブジェクト
	 */
	public void addColor(Color color) {
		if(color == null) { throw new IllegalArgumentException(); }
		this.colorList.add(color);
	}

	/**
	 * 色を表すオブジェクトのリストをレポートに追加する。
	 * @param color 色をあらわすオブジェクト
	 */
	public void addColor(ArrayList colorList) {
		if(colorList == null) { throw new IllegalArgumentException(); }

		Iterator it = colorList.iterator();
		while (it.hasNext()) {
			Color color = (Color) it.next();
			this.colorList.add(color);
		}
	}

	/**
	 * 色を表すオブジェクトのリストをクリアする。
	 */
	public void clearColorList() {
		this.colorList.clear();
		
	}

	/**
	 * ヘッダーの色を表すオブジェクトのリストを求める。
	 * @return color 色をあらわすオブジェクト
	 */
	public ArrayList getHeaderColorList() {
		ArrayList headerColorList = new ArrayList();
		Iterator it = this.colorList.iterator();
		while (it.hasNext()) {
			Color color = (Color) it.next();
			if(color.isHeader()){
				headerColorList.add(color);
			}
		}
		return headerColorList;
	}

	/**
	 * データテーブルの色を表すオブジェクトのリストを求める。
	 * @return color 色をあらわすオブジェクト
	 */
	public ArrayList getSpreadColorList() {
		ArrayList spreadColorList = new ArrayList();
		Iterator it = this.colorList.iterator();
		while (it.hasNext()) {
			Color color = (Color) it.next();
			if(!color.isHeader()){
				spreadColorList.add(color);
			}
		}
		return spreadColorList;
	}

	/**
	 * レポートを保存する。
	 * @param conn コネクションをあらわすオブジェクト
	 * @exception SQLException DBへのレポート保存処理で例外が発生した
	 */
	public void saveReport(Connection conn) throws SQLException {
		DAOFactory daoFactory = DAOFactory.getDAOFactory();

		ReportDAO reportDAO = daoFactory.getReportDAO(conn);
		reportDAO.saveReport(this, conn);
	}


	// ********** Setter メソッド **********

	/**
	 * レポート名をセットする。
	 * @param string レポート名
	 */
	public void setReportName(String string) {
		reportName = string;
	}

	/**
	 * レポートIDをセットする。
	 * @param string レポートID
	 */
	public void setParentID(String string) {
		parentID = string;
	}

	/**
	 * 新規レポートフラグをセットする。
	 * @param string レポートID
	 */
	public void setNewReport(boolean b) {
		isNewReport = b;
	}

	// ********** Getter メソッド **********

	/**
	 * レポート名を求める。
	 * @return レポート名
	 */
	public String getReportName() {
		return reportName;
	}

	/**
	 * レポートIDを求める。
	 * @return レポートID
	 */
	public String getReportID() {
		return reportID;
	}

	/**
	 * レポートの親ID（レポート格納するフォルダのID）を求める。
	 * @return レポートID
	 */
	public String getParentID() {
		return parentID;
	}

	/**
	 * キューブを求める。
	 * @return レポートID
	 */
	public Cube getCube() {
		return cube;
	}

	/**
	 * 軸オブジェクトのリストを求める。
	 * @return 軸オブジェクトのリスト
	 */
	public ArrayList getEdgeList() {
		return edgeList;
	}

	/**
	 * 色オブジェクトのリストを求める。
	 * @return 色オブジェクトのリスト
	 */
	public ArrayList getColorList() {
		return colorList;
	}

	/**
	 * 時間軸を持てばtrue、持たなければfalseを戻す。
	 * @return 軸オブジェクトのリスト
	 */
	public boolean hasTimeDim() {
		return hasTimeDim;
	}

	/**
	 * 新規作成中で未保存のレポートであればtrue、既存レポートであればfalseを戻す。
	 * @return 新規レポートか
	 */
	public boolean isNewReport() {
		return isNewReport;
	}

}
