/*
 * Created on 2003/05/01
 *
 */

package org.j69.eewiki.wiki;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.CharacterCodingException;
import java.util.Locale;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.oro.text.perl.Perl5Util;
import org.apache.struts.util.MessageResources;

import org.j69.eewiki.util.*;
import org.j69.eewiki.wiki.transformer.WikiTransformer;

/**
 * Wiki Main Class
 * Velocityから参照可能とするクラス
 * このクラスオブジェクトを参照してVelocityはページコンテンツを生成する
 */
public class Wiki {

	/**
	 * Logging output for this plug in instance.
	 */
	private Log log = LogFactory.getLog(this.getClass());

	private final HttpServletRequest request_;
	private final Locale locale_;
	private final MessageResources message_;
	private final String base_;
	private final String root_;
	private final String pageName_;
	private final boolean newPageFlag_;		//新規作成ページ

	private String contentType;
	private String actionType;

	//生データ保存フィールド
	private String rawData_ = "";

	//フォーマットページデータキャッシュ
	private String format_ = "";
	
	//ファイルデータオブジェクト
	private final WikiFile pageData_;		           //指定ページのデータオブジェクト

	// コンフィグ
	private final static CacheConfig config_ = CacheConfig.getInstance( );

	/**
	 * コンストラクタ
	 * @pageName ページ名
	 */
	public Wiki(String pageName, HttpServletRequest request, MessageResources message)
	throws WikiException, CharacterCodingException
	{
		newPageFlag_ = false;
		//定義情報の取得
		root_ = getRootPath();
		base_ = getBasePath();
		
		if (pageName == null || pageName  == "") {
			pageName_ =  getFrontPage();
		}
		else {
			pageName_ =WebUtil.getDecodeFileName(pageName.trim());
		}
		
		//一覧、履歴の場合はページコンテンツは作成しない
		if (pageName_.equals(config_.getConfig("define.pagename.list")) 
		    || pageName_.equals(config_.getConfig("define.pagename.new"))
		    ) {
			pageData_=null;
		}
		else {
			//ページオブジェクト生成
			pageData_ = new WikiFile(pageName_, true);
		}
		//Localeの取得
		request_ = request;
		locale_ = WebUtil.getLocale(request_);
		
		//メッセージの取得
		message_=message;
	}

	/**
	 * コンストラクタ 新規ページ作成用
	 * @pageName ページ名
	 */
	public Wiki(String pageName, boolean newPage, HttpServletRequest request, MessageResources message)
	throws WikiException, CharacterCodingException
	{
		//定義情報の取得
		root_ = getRootPath();
		base_ = getBasePath();

		newPageFlag_ = newPage;
		pageName_ = pageName.trim();
		pageData_= new WikiFile(pageName_, true);

		//Localeの取得
		request_ = request;
		locale_ = WebUtil.getLocale(request_);

		//メッセージの取得
		message_=message;
	}

	/**
	 * 履歴のリストを取得
	 * 
	 */
	public Vector getRecent() {
		//WikiListの作成
		WikiList wikilist = new WikiList(base_);
		Vector datas = wikilist.getWikiFiles(null, "date");
		return datas;
	}

	/**
	 * menuページの取得
	 **/
	public String getMenuContents() throws IOException {
		//Menu用 WikiFile
		String menupage = config_.getConfig("define.pagename.menu");
		WikiFile wikifile = new WikiFile(menupage, true);
		return getContentsByString(wikifile.getPageContent());
	}

	/**
	 * Formatページを専用キャッシュにセット
	 **/
	public void setFormatContents(Locale locale) throws IOException {
		//Format用 WikiFile
		String formatpage = "";
		Perl5Util perl = new Perl5Util();
		if (perl.match("m!^ja!", locale.getLanguage())) {
			formatpage = config_.getConfig("define.pagename.format") + "_ja";
		}
		else {
			formatpage = config_.getConfig("define.pagename.format");
		}
		WikiFile wikifile = new WikiFile(formatpage, true);
		format_ = getContentsByString(wikifile.getPageContent());
	}
	
	/**
	 * Formatページを専用キャッシュから取得
	 **/
	public String getFormatContents() {
		return format_;
	}

	/**
	 * Linkの取得（自分のページ名をキーに検索をした結果を返す）
	 **/
	public Vector getAutoLink() throws IOException {
		//WikiListの作成
		WikiList wikilist = new WikiList(base_);
		Vector datas = wikilist.getWikiFiles(getTitlename(), "title");
		return datas;
	}
		
	/**
	 * ページのフルパスを取得
	 *
	 * @return ページのフルパス
	 */
	public String getContentsPath() throws UnsupportedEncodingException {
		return pageData_.getContentsPath() ;
	}

	/**
	 * ページタイトルを取得
	 *
	 * @return ページタイトル
	 */
	public String getTitlename() {
		if (pageName_.equals(config_.getConfig("define.pagename.list")) 
   			|| pageName_.equals(config_.getConfig("define.pagename.new"))
			|| pageName_.equals(config_.getConfig("define.pagename.create"))
   			|| isNewPageFlag() == 1
			) {
				return pageName_;			
			}
			else {	
				return pageData_.getTitlename();
			}
	}

	/**
	 * ページリンク名を取得
	 *
	 * @return ページタイトル
	 */
	public String getLinkname() throws CharacterCodingException {
		if (pageName_.equals(config_.getConfig("define.pagename.list")) 
			|| pageName_.equals(config_.getConfig("define.pagename.new"))
			|| pageName_.equals(config_.getConfig("define.pagename.create"))
			|| isNewPageFlag() == 1
			) {
				return WebUtil.getEncodeFileName(pageName_);			
			}
			else {	
				return WebUtil.getEncodeFileName(pageData_.getTitlename());
			}
	}

	/**
	 * プロパティからフロントページタイトルの取得
	 *
	 * @return フロントページID
	 **/
	private String getFrontPage() {
		return config_.getConfig("define.pagename.toppage");
	}

	/**
	 * メイン処理
	 * Wiki用にページテキストを加工してHTML文字列を生成
	 */
	public String replaceWiki(String str) throws IOException {
		// TODO noformatの場合と切り分けること
		WikiList wikilist = new WikiList(base_);
		WikiTransformer trans = new WikiTransformer(base_, str, wikilist.getWikiFiles(null), request_, message_);
		String tmp = trans.transform();

		return tmp;
	}

	/**
	 * 未加工（テキストベース）のコンテンツ取得
	 */
	public String getPageContent() throws IOException {
		//新規ページならば空文字を返す
		if (newPageFlag_) {
			setCachePage("");
			return "";
		}
		String rawdata = pageData_.getPageContent();
		setCachePage(rawdata);
		return rawdata;
	}

	/**
	 * コンテンツ保存
	 */
	public void setPageContent(String contentText, boolean updateTime) throws IOException {
		
		if (contentText.trim().equals(null) || contentText.trim().equals("")) {
			//空の場合はページ削除と解釈
			pageData_.deleteFile(); 
		}
		else {
			//ページ保存
			pageData_.setPageContent(contentText, updateTime);
		}
	}

	/**
	 * 編集可能なページかどうか？
	 *
	 * @return 1:編集可能なページ、0:編集できないページ
	 **/
	public int isFixedPage() {
		if (pageData_.isFixedPage())
			return 1;
		return 0;
	}

	/**
	 * パスワードが必要なページかどうか
	 *
	 * @return 1:パスワードが必要なページ、0:パスワードが必要ないページ
	 **/
	public int isUsepasswd() {
		if (pageData_.isUsepasswd()) 
			return 1;
		return 0;
	}
	
	/**
	 * ページの存在チェック
	 *
	 * @return Ture:ある False:ない
	 **/
	public boolean isExist() {
		return pageData_.isExists();
	}

	/**
	 * ページ文字列取得（ページID自動）
	 */
	public String getContents() throws IOException {
		String rawdata = pageData_.getPageContent();
		setCachePage(rawdata);
		return getContentsByString(rawdata);
	}

	/**
	 * ページ文字列取得（文字列指定）
	 */
	public String getContentsByString(String str)
	throws IOException {
		return replaceWiki(str);
	}

   	/**
	 * ページ文字列取得（ページID指定）
	 */
	public String getText() throws IOException {
		String rawdata = pageData_.getPageContent();
		setCachePage(rawdata);
		return rawdata;
	}

	/**
	 * ページスタイル文字列取得
	 */
	public String getStylePath() throws IOException {
		return pageData_.getStylePath();
	}

	/**
	 * ページスタイル文字列取得
	 */
	public String getDefaultStylePath() {
		String dirName = config_.getConfig("define.dir.css");
		String fileName = config_.getConfig("define.page.style");
		return dirName + "/" + fileName + ".css";
	}

	/**
	 * サブタイトル取得
	 */
	public String getSubtitlename() throws IOException {
		return pageData_.getSubtitlename();
	}

	/**
	 * 最終更新日時取得（文字列）
	 */
	public String getLastModified() {
		return pageData_.getLastmodifiedAsString(locale_);
	}

	/**
	 * 経過時間取得
	 */
	public String getPassage() {
		return pageData_.getPassage();
	}

	/**
	 * 更新可能か？
	 * ファイルの最終更新時間が変更されていたら
	 * 他者がファイルをUPDATEしていると判断
	 */
	public boolean isUpdatable(String lastModified) throws WikiException {
		String fileLastModified = String.valueOf(pageData_.getLastModified());
		return lastModified.equals(fileLastModified);
	}

	/**
	 * メニューを使用するかどうか
	 */
	public int isUseMenu() {
		if (config_.getConfigAsBoolean("define.page.menu")) 
			return 1;
		return 0;
	}

	/**
	 * Modeyfied By
	 * 編集者
	 */
	public String getModifiedBy() {
		return config_.getConfig("define.modifier");
	}

	/**
	 * Modeyfied Link
	 * 編集者のリンク
	 */
	public String getModifiedLink() {
		return config_.getConfig("define.modifier.link");
	}

	/**
	 * 汎用プロパティ取得
	 * @return CacheProperties
	 */
	public String getConfig(String name) {
		return config_.getConfig(name);
	}

	/**
	 * 新規ページかどうか
	 * @return
	 */
	public int isNewPageFlag() {
		if (isExist())
			return 0;
		return 1;
	}

	/**
	 * 定義情報からeeWiki-Rootディレクトリの取得
	 * @return
	 */
	public String getRootPath() {
		//定義情報の取得
		return config_.getConfig("define.wiki.basedir");
	}
	
	/**
	 * 定義情報からデータディレクトリの取得
	 * @return
	 */
	public String getBasePath() {
		//定義情報の取得
		return getRootPath() + config_.getConfig("define.dir.data");
	}

	/**
	 * 添付ファイル機能が有効かどうか
	 * @return
	 */
	public int isUseUpload() {
		//定義情報の取得
		if (config_.getConfigAsBoolean("define.upload")) 
			return 1;
		return 0;
	}
	
	/**
	 * ページに紐づく添付ファイルリストの取得
	 * @return
	 */
	public Vector getAttList() throws IOException  {
		if (getCachePage(1).equals(null) || getCachePage(1).equals(""))
			return null;
		return WikiAttachment.getAttList(getCachePage(1));
	}

	/**
	 * 添付ファイルリスト一覧の取得
	 * @return
	 */
	public Vector getAttAllList() {
		return WikiAttachment.getAllList();
	}

	/**
	 * ページ名を物理ファイル名へ
	 * @return
	 */
	public String getEncodeFileName(String filename) throws CharacterCodingException {
		return WebUtil.getEncodeFileName(filename);
	}

	/**
	 * 物理ファイル名をページ名へ
	 * @return
	 */
	public String getDecodeFileName(String phyfilename) {
		return WebUtil.getDecodeFileName(phyfilename);
	}

	/**
	 * 凍結設定
	 */
	public void setFrozen() throws IOException {
		pageData_.setFrozen();
	}

	/**
	 * 解凍設定
	 */
	public void setMelts() throws IOException {
		pageData_.setMelts();
	}

	/**
	 * 凍結ページか？
	 * @return
	 */
	public int isFrozen() throws IOException {
		if (pageData_.isFrozen())
			return 1;
		return 0;
	}

	/**
	 * ページコンテンツのキャッシュ
	 * @rawData ページデータ（生データ）
	 * 
	 */
	public void setCachePage(String rawData) {
		rawData_ = rawData.replaceAll("\r\n", "\n");
	}

	/**
	 * ページコンテンツのキャッシュ
	 * @isRawData 0:HTML化したデータ 1:生データ 
	 * @return　ページデータ
	 */
	public String getCachePage(int isRawData) throws IOException {
		if (isRawData == 1) 	
			return rawData_;
		return replaceWiki(rawData_);
	}

	/**
	 * 差分のデータの取得
	 * @return　ページデータ
	 */
	public String diffWiki() throws IOException  {
		return pageData_.diffWiki();
	}

	/**
	 * ローケルを取得
	 * @return　ローケル
	 */
	public Locale getLocale() {
		return locale_;
	}

	/**
	 * ページの行数の取得
	 * @return　ページの行数（だいたい...汗）
	 */
	public int getPageRows() throws IOException {
		String data = getCachePage(1);
		String[] datas = data.split("\n");
		return datas.length;
	}

}
