/*  OpenOlap viewer
 *  パッケージ名：openolap.viewer.export
 *  ファイル：ExportReportAsCSV.java
 *  説明：CSV形式でレポートをエクスポートするクラスです。
 *
 *  作成日: 2004/01/31
 */
package openolap.viewer.export;

import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import openolap.viewer.Axis;
import openolap.viewer.AxisMember;
import openolap.viewer.CellData;
import openolap.viewer.Col;
import openolap.viewer.Report;
import openolap.viewer.Row;
import openolap.viewer.common.Constants;
import openolap.viewer.common.Messages;
import openolap.viewer.common.StringUtil;
import openolap.viewer.controller.RequestHelper;
import openolap.viewer.dao.DAOFactory;
import openolap.viewer.manager.CellDataManager;

/**
 *  クラス：ExportReportAsCSV
 *  説明：CSV形式でレポートをエクスポートするクラスです。
 */
public class ExportReportAsCSV extends ExportReport {

	/**
	 * エクスポート処理を実行し、ダウンロードページのパスを戻す。
	 * @param helper RequestHelperオブジェクト
	 * @return dispatch先のJSP/HTMLのパス
	 */
	public String exportReport(RequestHelper helper) {

		HttpServletRequest request = helper.getRequest();
		Report report = (Report) helper.getRequest().getSession().getAttribute("report");
		if (report==null) {
			throw new IllegalStateException();
		}

		// ファイルパス、ファイルURLを設定
		String dirPath = helper.getConfig().getServletContext().getRealPath("/") + "export";
		String fileName = "report" + request.getSession().getId() + ".csv";
		String filePath = dirPath + "/" + fileName;
		String fileURL = request.getContextPath() + "/" + Messages.getString("ExportReportAsCSV.exportTmpDir") + "/" + fileName; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		helper.getRequest().setAttribute("downloadURL", fileURL);

		DAOFactory daoFactory = DAOFactory.getDAOFactory();
		Connection conn = null;
		conn = daoFactory.getConnection();

		FileOutputStream fs = null;
		OutputStreamWriter osw = null;
		PrintWriter out = null;

		try {

			// =============== 共通情報を取得 ===============

			// 行・列に配置された全DimensionオブジェクトにDimensionMemberオブジェクトをセット
			report.setSelectedCOLROWDimensionMembers(helper, report, conn);

			// セルデータ(値はフォーマット付)を取得
			ArrayList cellDataList = CellDataManager.selectCellDatas(helper, conn, true);
			// セルデータをテーブル形式にソートし直したもの
			TreeMap dataRowMap = CellDataManager.getCellDataTable(report, cellDataList);

			// エッジ
			Col col = (Col) report.getEdgeByType(Constants.Col);
			Row row = (Row) report.getEdgeByType(Constants.Row);
			
			// エッジの持つ軸リスト
			ArrayList colAxesList = col.getAxisList();
			ArrayList rowAxesList = row.getAxisList();
			ArrayList pageAxesList = report.getEdgeByType(Constants.Page).getAxisList();

			// 軸が持つメンバー数
			ArrayList colAxisMembersList = new ArrayList();
			ArrayList rowAxisMembersList = new ArrayList();


			String colIndexKeysString = (String)request.getSession().getAttribute("viewColIndexKey_hidden");
			String rowIndexKeysString = (String)request.getSession().getAttribute("viewRowIndexKey_hidden");

			// =============== CSVファイル生成処理開始 ===============
			fs = new FileOutputStream(filePath, false);	//既存のファイルがある場合、上書きする
			osw = new OutputStreamWriter(fs,"Shift_JIS");
			out = new PrintWriter(new BufferedWriter(osw));


			// =============== CSV出力開始 ===============

			// レポートタイトル
			out.println(report.getReportName());

			// ページエッジ軸名, ページエッジデフォルトメンバー名
			String pageAxisName = ",";
			String memberName = "選択メンバー,";
			Iterator pageIt = pageAxesList.iterator();
			int i = 0;
			int j = 0;
			int k = 0;
			while (pageIt.hasNext()) {
				if(i>0){
					pageAxisName += ",";
					memberName += ",";
				}
				Axis axis = (Axis) pageIt.next();
				pageAxisName += axis.getName();
				memberName += axis.getDefaultMemberName(conn);
				i++;
			}
			out.println(pageAxisName);
			out.println(memberName);

			out.println();	// 空行

			// 列ヘッダの軸名リスト
			String colAxisName = null;
				colAxisName = StringUtil.addString("","first",rowAxesList.size(),",");
			Iterator colIt = colAxesList.iterator();
			i = 0;
			while (colIt.hasNext()) {
				if (i>0) {
					colAxisName += ",";
				}
				Axis axis = (Axis) colIt.next();
				colAxisName += axis.getName();
				i++;
			}
			out.println(colAxisName);

			// クロスヘッダ部、列ヘッダ部出力

			// 行ヘッダの軸名リスト生成
			String rowAxisName = "";
			Iterator rowIt = rowAxesList.iterator();
			i = 0;
			while (rowIt.hasNext()) {
				if (i>0) {
					rowAxisName += ",";
				}
				Axis axis = (Axis) rowIt.next();
				rowAxisName += axis.getName();
				i++;
			}

			colIt = colAxesList.iterator();
			i = 0;
			while (colIt.hasNext()) {
				Axis colAxis = (Axis) colIt.next();
				int colMergeNum = getCellMergeNum(col, colAxis)+1;	// セル結合するセルの数

				// ===== クロスヘッダ部 =====
				if (i == (colAxesList.size()-1)) {	// 最終段の場合、軸タイトルを表示
						out.print(rowAxisName);
				} else {
					out.print(StringUtil.addString("", "first", rowAxesList.size()-1, ","));
				}

				// ===== 列ヘッダ部(メンバー名を出力) =====

				// SpreadIndexの順でソート
				TreeMap colIndexKeyMap = new TreeMap();
				ArrayList colIndexKeyList = StringUtil.splitString(colIndexKeysString, ",");
				Iterator colIndexKeyIt = colIndexKeyList.iterator();

				while (colIndexKeyIt.hasNext()) {
					String colIndexKey = (String) colIndexKeyIt.next();
					ArrayList colIndexKeys = StringUtil.splitString(colIndexKey, ":");
					String index = (String) colIndexKeys.get(0);
					Integer ind  = Integer.decode(index);
					String keys = (String) colIndexKeys.get(1);
					colIndexKeyMap.put(ind, keys);
				}

				Iterator colIndexKeyMapIt = colIndexKeyMap.keySet().iterator();

				String beforeKey = null;
				String beforeKeys = null;
				int mergeNum = 0;
				j = 0;
				while (colIndexKeyMapIt.hasNext()) {

					Integer index = (Integer) colIndexKeyMapIt.next();
					String keys = (String) colIndexKeyMap.get(index);

					ArrayList keyList = StringUtil.splitString(keys, ";");
					String key = (String) keyList.get(i);

					if (isJoinMember(beforeKeys, keys, i)) {
						mergeNum++;
					} else {

						if ( j != 0 ) {
//System.out.println(i + "," + j + "," + colAxis.getAxisMemberByUniqueName(beforeKey).getSpecifiedDisplayName(colAxis) + mergeNum);

							out.print(",");
							out.print("\"" + colAxis.getAxisMemberByUniqueName(beforeKey).getSpecifiedDisplayName(colAxis) + "\"");
							out.print(StringUtil.addString("", "first", mergeNum, ",")); // セルの幅の分だけ","を出力

						}

						beforeKey = key;
						beforeKeys = keys;
						mergeNum = 0;
					}

					j++;
				}

				// 最後の要素を表示する
				if (j > 0) { // 列ヘッダの要素が一つ以上存在した
					out.print(",");
				}

				out.print("\"" + colAxis.getAxisMemberByUniqueName(beforeKey).getSpecifiedDisplayName(colAxis) + "\"");
				out.print(StringUtil.addString("", "first", mergeNum, ",")); // セルの幅の分だけ","を出力

				// 行出力の終了タグ
				out.println();
				i++;
			}

	
			// ===== 行ヘッダ部(メンバー名)、データセル部(値)出力 =====

			// SpreadIndexの順でソート
			TreeMap rowIndexKeyMap = new TreeMap();
			ArrayList rowIndexKeyList = StringUtil.splitString(rowIndexKeysString, ",");
			Iterator rowIndexKeyIt = rowIndexKeyList.iterator();

			while (rowIndexKeyIt.hasNext()) {
				String rowIndexKey = (String) rowIndexKeyIt.next();
				ArrayList rowIndexKeys = StringUtil.splitString(rowIndexKey, ":");
				String index = (String) rowIndexKeys.get(0);
				Integer ind  = Integer.decode(index);
				String keys = (String) rowIndexKeys.get(1);
				rowIndexKeyMap.put(ind, rowIndexKey);
			}

			// ArrayListに持ち直し
			Iterator rowIndexKeyMapIt = rowIndexKeyMap.keySet().iterator();
			ArrayList sortedIndexKeyList = new ArrayList();
			while (rowIndexKeyMapIt.hasNext()) {
				Integer ind = (Integer) rowIndexKeyMapIt.next();
				sortedIndexKeyList.add( rowIndexKeyMap.get(ind));
			}


			Iterator rowIndexIt = sortedIndexKeyList.iterator();
			String beforeKeys = null;
			int rowIndex = 0;
			while (rowIndexIt.hasNext()) {
				String rowIndexKey = (String) rowIndexIt.next();
				ArrayList rowIndexKeys = StringUtil.splitString(rowIndexKey, ":");
				String index = (String) rowIndexKeys.get(0);
				Integer ind  = Integer.decode(index);
				String keys = (String) rowIndexKeys.get(1);
				ArrayList keyList = StringUtil.splitString(keys, ";");

				// 行ヘッダー出力
				for (i = 0; i < rowAxesList.size(); i++ ){

					if (!this.isJoinMember(beforeKeys, keys, i)) { 
						Axis rowAxis = (Axis) rowAxesList.get(i);
						String key = (String) keyList.get(i);
						AxisMember axisMember = (AxisMember) rowAxis.getAxisMemberByUniqueName(key);

						out.print("\"" + axisMember.getSpecifiedDisplayName((Axis)rowAxesList.get(i)) + "\"");
						out.print(","); // 次のセルとの区切り（次段の行ヘッダメンバーセルもしくはデータテーブルセル）
					} else {
						out.print(","); // このセルは結合対象となるセルであり、名称は表示しないが、区切り文字は出力する
					}
				}

				// データテーブル部出力
				this.printDataRow(dataRowMap, rowIndex, out);

				beforeKeys = keys;
				rowIndex++;
			}
			
			// 改行
			out.println();

			out.flush();
			osw.flush();
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {

			if (fs != null) {
				try {
					fs.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}

			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e1) {
					e1.printStackTrace();
				}
			}

		}

		// 一時保存したディメンションメンバー情報を削除する
		report.clearDimensionMembers();
		return "/spread/downloadAct.jsp";

	}

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

	/**
	 * データテーブル部を一行出力する
	 * @param dataRowMap データ行をあらわすMapオブジェクト
	 * @param newRowIndex 出力する列のインデックス
	 * @param out PrintWriterをあらわすオブジェクト
	 */
	private void printDataRow(TreeMap dataRowMap, int newRowIndex, PrintWriter out) {

		// 取得対象となる行のクライアント側でのSpreadIndexの値と、取得対象となる行に対して、通番で振られるIndexを変換する
		ArrayList oldRowIndex = new ArrayList(dataRowMap.keySet());
		TreeMap dataCellMap = (TreeMap) dataRowMap.get(oldRowIndex.get(newRowIndex));
		Iterator dataCellIt = dataCellMap.keySet().iterator();
		int i = 0;
		while (dataCellIt.hasNext()) {
			Integer colIndex = (Integer) dataCellIt.next();
			String value = "\"" + ( (CellData)dataCellMap.get(colIndex) ).getValue() + "\"";

			if (i>0) {
				out.print(",");
			}
			out.print(value);
			i++;
		}
		// 改行
		out.println();
	}

}
