// Aqsis
// Copyright (c) 1997 - 2001, Paul C. Gregory
//
// Contact: pgregory@aqsis.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/**
 * Copyright (C) 2006-2007  NTT DATA CORPORATION
 * 
 * Version: 1.0.0 2007/04/01
 *  
 */
package net.cellcomputing.himawari.library.types;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;

import net.cellcomputing.himawari.util.HimawariLogger;

/**
 * 
 * ファイルを扱うクラス。
 * ワイルドカード検索、絶対ファイル名の取得、ファイル長の取得、ヌルチェックなどをサポートする。
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqFile {

	private RandomAccessFile	m_pStream;
	private String				m_strRealName;
	
	/**
	 * デフォルトコンストラクタ
	 */
	public CqFile()
	{
		m_pStream	= null;
	}
	
    /**
     * ファイルとその実体名を指定して初期化する
     * 
     * @param Stream	既に開かれたRandomAccessFileオブジェクト
     * @param strRealName	ファイル名
     */
    public CqFile( RandomAccessFile Stream, final String strRealName )
    {
    	m_pStream		= Stream;
    	m_strRealName	= strRealName;
    }

    /**
     * 検索パスを指定してファイルを開くコンストラクタ
     * 
     * @param strFilename	開きたいファイル名
     * @param strSearchPathOption	検索パス
     */
    public CqFile( final String strFilename, final String strSearchPathOption )
    {
    	m_pStream = null;
    	Open( strFilename, strSearchPathOption );
    }
    
    /**
     * ファイルを開くコンストラクタ。<br>
     * カレントディレクトリのファイルを開く。
     * 
     * @param strFilename	開きたいファイル名
     */
    public CqFile( final String strFilename )
    {
    	m_pStream = null;
    	Open( strFilename, "" );
    }
	
	
	//************************************************************************//
	//*** メソッドの定義
	//************************************************************************//
	
    /**
     * 検索パスを指定してファイルを開く。<br>
     * まずはカレントを探し、なければ検索パスを探す。
     * 
     * @param strFilename	開きたいファイル名
     * @param strSearchPathOption	検索パス
     * @param mode	オープンモード（"r","rw"）
     */
    public void Open( String strFilename, final String strSearchPathOption, final String mode )
    {
    	//nttdata 追加 2006/03/16 
    	strFilename = FixupPath(strFilename);
    	
    	//まずはカレントディレクトリをサーチ
    	m_strRealName = strFilename;
    	RandomAccessFile pFStream = null;
    	
    	try {
			pFStream = new RandomAccessFile( strFilename, mode );
			
			m_pStream = pFStream;
			return;
			
		} catch (FileNotFoundException e) {		//if ( !pFStream->is_open() )
			
			//サーチパスが指定されていればそこをサーチ
			if( !strSearchPathOption.equals("") )
			{

				//パス文字列は":"で区切られているので、その中から探す
				int len = 0;
				int start = 0;
		    	String strPath = "";

				while( true ){
					
					// Find the next search path in the spec.
					int index = strSearchPathOption.indexOf( ':', start );
					if( index==-1 )
						index = strSearchPathOption.length();
					len = index - start;
					
	                // Check if it is realy meant as a drive spec.
					
	                if ( len == 1 && Character.isLetter( strSearchPathOption.charAt(start) ) ) {
	                	int separatePos = strSearchPathOption.indexOf( ':', start+2 );
	                	if( separatePos==-1 ){
	                		len = strSearchPathOption.length() - start;
	                	}
	                	else{
	                		len = separatePos - start;
	                	}
	                }
	                strPath = strSearchPathOption.substring( start, start+len );
//	                if ( strPath == "" ) break;
	                if ( strPath.equals( "" ) ) break;
					
	                // Apply any system specific string modification.
	                strPath = FixupPath( strPath );
	                
					//サーチパス＋ファイル名を作成
					String strAlternativeFilename = strPath;
					if( !strAlternativeFilename.endsWith(File.separator) ){
						strAlternativeFilename += File.separator;
					}
					strAlternativeFilename += strFilename;
					
					//ファイルの有無を確認
					File file = new File( strAlternativeFilename );
					if( file.isFile() )
					{
						//ファイルオープン
						try {
							pFStream = new RandomAccessFile( file, "r" );
							
							//開けたらそれをメンバ変数にセット
							m_pStream = pFStream;
							m_strRealName = strAlternativeFilename;
							
							return;
							
						} catch (FileNotFoundException e1) {
							m_pStream = null;
							
						}//end of try for FileOpen
					}
					
					//次のループへ。
					if( start + len < strSearchPathOption.length() ){
						start += len + 1; 
					}
					else{
						break;
					}
			
					
				}//end of while( ";:" )
			}
		}
    	
    }
    
    /**
	 * 
	 * RATなどから出力される、特殊なパス指定を吸収するためのメソッド<br>
	 * 指定パス文字列が、特殊形式でなければそのまま返す。
	 * 
	 * @param strPath	パス文字列
	 * @return	正当に修正されたパス文字列
	 */
	private String FixupPath(String strPath) {
	    
		if( strPath.startsWith("//") )
	    {
	        if(strPath.charAt(3) == '/')
	        {
	            String strNewPath = strPath.substring(2,3);
	            strNewPath = strNewPath.concat(":/");
	            strNewPath = strNewPath.concat( strPath.substring(4) );
	            //std::cout << strNewPath.c_str() << std::endl;
	            return(strNewPath);
	        }
	    }

	    return( strPath );
	    
	}

	/**
     * 検索パスを指定して読み込み専用ファイルを開く。<br>
     * まずはカレントを探し、なければ検索パスを探す。
     * 
     * @param strFilename	開きたいファイル名
     * @param strSearchPathOption	検索パス
     */
    public void Open( final String strFilename, final String strSearchPathOption )
    {
    	Open( strFilename, strSearchPathOption, "r" );
    }
    
    /**
     * ファイルを開く。<br>
     * カレントディレクトリのファイルを開く。
     * 
     * @param strFilename	開きたいファイル名
     */
    public void Open( final String strFilename )
    {
    	Open( strFilename, "", "r" );
    }

    /**
     * ファイルを閉じる
     * 
     */
    public void Close()
    {
        if ( m_pStream != null ){
        	try {
				m_pStream.close();
			} catch (IOException e) {
				HimawariLogger.outputException( e );
			}
        }
        m_pStream = null;
    }

    /**
     * ファイルオブジェクトがnullかどうかチェックする
     * 
     * @return	true：ファイルファイルオブジェクトはnull
     * 			false:ファイルオブジェクトは開かれている
     */
    public boolean IsValid()
    {
        return ( m_pStream != null );
    }
    
    /**
     * ファイル名の取得
     * 
     * @return	ファイル名
     */
    public final String strRealName()
    {
        return ( m_strRealName );
    }
    
    /**
     * ファイルポインタの位置を取得
     * 
     * @return	ファイルポインタの位置
     */
    public long Position()
    {
        try {
			return ( m_pStream.getFilePointer() );
			
		} catch (IOException e) {
			HimawariLogger.outputException( e );
			return -1;
		}
    }
    
    /**
     * ファイルサイズの取得
     * 
     * @return	ファイルサイズ（バイト単位）
     */
    public long Length()
    {
    	if( m_pStream == null )		return -1;
    	
        try {
			return m_pStream.length();
			
		} catch (IOException e) {
			HimawariLogger.outputException( e );
			return -1;
		}
    }

//    public String FixupPath( String strPath )
//    {
//        if( strPath.find("//",0,2) == 0 )
//        {
//            if(strPath[3] == '/')
//            {
//                CqString strNewPath(strPath.substr(2,1));
//                strNewPath.append(":/");
//                strNewPath.append(strPath.substr(4));
//                //std::cout << strNewPath.c_str() << std::endl;
//                return(strNewPath);
//            }
//        }
//
//        return( strPath );
//    }

    /**
     * 
     * ワイルドカードを利用してファイルの一覧を検索する。
     * 
     * @param strFileGlob	検索ファイル名（ワイドカード利用可）
     * @return	検索結果のリスト
     */
    static public ArrayList<String> Glob( final String strFileGlob )
    {
    	File hFile;
    	String pt = strFileGlob.trim();
    	
    	ArrayList<String> result = new ArrayList<String>();
    	int dp = pt.lastIndexOf(File.separator);
    	if( dp == -1 )
    	{
    		pt = "." + pt;
    		dp = 1;
    	}
    	else{
    		dp += File.separator.length();
    	}
    		hFile = new File( pt.substring(0,dp) );
//    		hFile = new File( pt );
    		if( hFile.exists() )
    		{
    			//正規表現によるファイルサーチ
    			String[] strFile;
    			strFile = hFile.list( new GlobFileFilter( pt.substring(dp) ) );
//    			strFile = hFile.list( new GlobFileFilter( pt ) );
    			
    			for( String str : strFile ){
    				result.add( str );
    			}
    		}
    		
//    	}
    	
    	return result;
    }
	
	
	//************************************************************************//
	//*** 演算子のオーバーロード
	//************************************************************************//
	
    /**
     * 参照演算子。 <br>
     * 現在のファイルを返す。
     * 
     * @return	開いているファイル
     */
    public RandomAccessFile ref(){
    	return ( m_pStream );
    }
    
	/**
	 * ポインタ演算子。,br>
     * 現在のファイルを返す。
     * 
     * @return	開いているファイル
	 */
	public RandomAccessFile point(){
		return ( m_pStream );
	}
	
	
	
	// 2006/03/16 書き込み変換対応
	public static String FixupPathIfNeed(String path){
		CqFile file = new CqFile();
		return file.FixupPath(path);
	}
	
}
