/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.hayabusa.servlet;

// import jakarta.servlet.http.HttpSession;					// 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応

import org.opengion.fukurou.system.OgRuntimeException ;		// 6.4.2.0 (2016/01/29)
import static org.opengion.fukurou.system.HybsConst.CR ;	// 6.1.0.0 (2014/12/26)
import org.opengion.fukurou.util.FileUtil;
import org.opengion.fukurou.util.FileInfo;					// 6.2.0.0 (2015/02/27)
import org.opengion.fukurou.util.StringUtil;				// 6.0.2.4 (2014/10/17)

// import org.opengion.hayabusa.common.HybsSystem;			// 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応
// import org.opengion.hayabusa.io.StorageAPI;				// 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応
// import org.opengion.hayabusa.io.StorageAPIFactory;		// 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応
import org.opengion.hayabusa.io.HybsFileOperationFactory;	// 8.0.0.0 (2021/09/30)

import java.io.File;

/**
 * ﾌｧｲﾙをｻｰﾊﾞｰにｱｯﾌﾟﾛｰﾄﾞする場合に使用されるﾌｧｲﾙ管理ｸﾗｽです｡
 * HTML5 ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞの複数選択（multiple）対応 に伴い､一つのｸﾗｽとして public化します｡
 *
 * @og.group その他機能
 * @og.rev 5.7.1.1 (2013/12/13) HTML5 ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞの複数選択（multiple）対応
 * @og.rev 5.9.25.0 (2017/10/06) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ追加対応
 *
 * @version  4.0
 * @author	 Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public final class UploadedFile implements Comparable<UploadedFile> {

	/** ﾊﾞｯﾌｧの初期容量を通常より多い目に設定します｡  {@value}  */
	public static final int BUFFER_MIDDLE = 200;

	// 5.9.25.0 (2017/10/06) MODIFY File型をString型に変更
	private String filename	;				// 現時点での置き換え後ﾌｧｲﾙ名

	private final String uniqKey	;		// ｱｯﾌﾟﾛｰﾄﾞされたﾌｧｲﾙ名(ﾕﾆｰｸにしておきます)
	private final String dir		;
	private final String name		;
	private final String original	;
	private final String type		;

	/**
	 * ｱｯﾌﾟﾛｰﾄﾞﾌｧｲﾙの管理ｵﾌﾞｼﾞｪｸﾄを作成します｡
	 *
	 * @og.rev 5.7.1.1 (2013/12/13) HTML5 ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞの複数選択（multiple）対応
	 *
	 * @param	uniqKey		ﾕﾆｰｸｷｰ(初期ｱｯﾌﾟﾛｰﾄﾞﾌｧｲﾙ名)
	 * @param	dir			ﾌｧｲﾙを保管するﾌｫﾙﾀﾞ
	 * @param	name		ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞされた時のname属性
	 * @param	original	ﾌｧｲﾙ名(ｵﾘｼﾞﾅﾙ)
	 * @param	type		ｺﾝﾃﾝﾄﾀｲﾌﾟ
	 */
	UploadedFile( final String uniqKey, final String dir, final String name, final String original, final String type ) {
		this.uniqKey	= uniqKey;		// 5.7.1.1 (2013/12/13) uniqKey を確定させる｡
		this.dir		= dir;
		this.name		= name;
		this.original	= original;
		this.type		= type;
	}

	/**
	 * ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞされた時のname属性を取得します｡
	 *
	 * @og.rev 5.7.1.1 (2013/12/13) HTML5 ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞの複数選択（multiple）対応
	 *
	 * @return	ﾌｧｲﾙｱｯﾌﾟﾛｰﾄﾞされた時のname属性
	 */
	public String getName() {
		return name;
	}

	/**
	 * ｺﾝﾃﾝﾄﾀｲﾌﾟを取得します｡
	 *
	 * @return	ｺﾝﾃﾝﾄﾀｲﾌﾟ
	 */
	public String getContentType() {
		return type;
	}

	/**
	 * ﾌｧｲﾙ名(置き換え後)を取得します｡
	 *
	 * @og.rev 5.7.1.2 (2013/12/20) zip 対応で､Fileｵﾌﾞｼﾞｪｸﾄを返すようにします｡
	 * @og.rev 5.9.25.0 (2017/10/06) FILE型をString型に変更
	 *
	 * @return	ﾌｧｲﾙ名(置き換え後)
	 */
	public String getUploadFile(){
		return filename;
	}

	/**
	 * Fileｵﾌﾞｼﾞｪｸﾄ(置き換え後)を取得します｡
	 *
	 * @og.rev 8.1.2.0 (2022/03/10) Fileｵﾌﾞｼﾞｪｸﾄを返すようにします｡
	 *
	 * @param	useLocal	強制的にﾛｰｶﾙﾌｧｲﾙを使用する場合､true にｾｯﾄします｡
	 *
	 * @return	Fileｵﾌﾞｼﾞｪｸﾄ(置き換え後)
	 */
	public File getFile( final boolean useLocal ) {
		return HybsFileOperationFactory.create( useLocal, dir, filename );
	}

	/**
	 * ﾌｧｲﾙ名(置き換え後)の置き換えを実行します｡
	 * useBackup = true にすると､dir の直下に､"_backup" ﾌｫﾙﾀﾞを作成します｡
	 * ﾊﾞｯｸｱｯﾌﾟﾌｧｲﾙ名は､元のﾌｧｲﾙ名(拡張子含む) ＋ "_" + 現在時刻のlong値 + "." + 元のﾌｧｲﾙの拡張子
	 *
	 * newName が null の場合は､original のﾌｧｲﾙ名に､変換します｡
	 *
	 * 6.0.2.4 (2014/10/17)
	 * useBackup="rename" で､すでに同名のﾌｧｲﾙが存在した場合に､"_001" のような文字列を追加したﾌｧｲﾙにﾘﾈｰﾑします｡
	 * Windowsの " - ｺﾋﾟｰ (2)" に近いですが､桁数を抑えるのと､useBackup="true" と異なり､過去の同一ﾌｧｲﾙ名は
	 * そのまま､有効になります｡同一ﾌｧｲﾙが同一ﾌｫﾙﾀﾞに存在する場合のみ連番が付与されます｡
	 *
	 * newName の指定に､ﾌｫﾙﾀﾞ名を含めることを可能にしました｡
	 *
	 * @og.rev 5.7.1.1 (2013/12/13) 新規追加
	 * @og.rev 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた｡
	 * @og.rev 6.0.2.4 (2014/10/17) useBackup 修正､newName に､ﾌｫﾙﾀﾞ名を含めることが可能
	 * @og.rev 6.2.0.0 (2015/02/27) FileInfoｸﾗｽを使用｡ (FileUtil#getExtension(String) の廃止)
	 * @og.rev 5.9.25.0 (2017/10/06) returnをString型に変更｡引数にfileURLとsessionを追加
	 * @og.rev 5.10.9.0 (2019/03/01) ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ対応の追加｡
	 * @og.rev 8.0.1.0 (2021/10/29) useLocal 属性を追加｡storageType , bucketName 削除
	 *
	 * @param	newName		ﾌｧｲﾙ名(nullの場合は､ｵﾘｼﾞﾅﾙ)
	 * @param	prefix		接頭辞(nullの場合は､何もつけない)
	 * @param	sufix		接尾辞(nullの場合は､何もつけない)
	 * @param	useBackup	置き換え後ﾌｧｲﾙの処理方法(true:backupﾌｫﾙﾀﾞ/false:しない/rename:重複しない連番)
	 * @param	fileURL		ｸﾗｳﾄﾞｽﾄﾚｰｼﾞ用のURL
//	 * @param	hsession	ｾｯｼｮﾝ
//	 * @param	storage		ｸﾗｳﾄﾞﾌﾟﾗｸﾞｲﾝ名(ﾛｰｶﾙﾌｧｲﾙを強制する場合は､LOCAL を指定する)
//	 * @param	bucket		ﾊﾞｹｯﾄ名(ﾛｰｶﾙﾌｧｲﾙを強制する場合は､LOCAL を指定する)
	 * @param	useLocal	強制的にﾛｰｶﾙﾌｧｲﾙを使用する場合､true にｾｯﾄします｡
	 * @return	最終的に作成されたﾌｧｲﾙｵﾌﾞｼﾞｪｸﾄ
	 */
//	public String renameTo( final String newName , final String prefix , final String sufix , final String useBackup, final String fileURL, final HttpSession hsession ) {
	public String renameTo( final String newName , final String prefix , final String sufix , final String useBackup, final String fileURL,
//				final String storage, final String bucket ) {
				final boolean useLocal ) {

		// 6.0.2.4 (2014/10/17) prfix が null でなければ､連結｡newName が null なら､original を使う｡
		String newNm = StringUtil.nvalAdd( prefix, StringUtil.coalesce( newName,original ) );

		if( newNm == null || newNm.isEmpty() ) {
			final String errMsg = "新ﾌｧｲﾙ名が存在しません｡[" + newNm + "]" ;
			throw new OgRuntimeException( errMsg );
		}

		// 新ﾌｧｲﾙ名から拡張子取得
		final String newExt = FileInfo.getSUFIX( newNm );			// 6.2.3.0 (2015/05/01)
		if( newExt == null || newExt.isEmpty() ) {								// 拡張子なし
			final String oldExt = FileInfo.getSUFIX( original );
			newNm = StringUtil.nvalAdd( newNm , sufix , "." , oldExt ) ;		// sufix を入れ込む｡
		}
		else if( sufix != null ) {												// 拡張子あり､sufixあり
			final StringBuilder buf = new StringBuilder( newNm );
			buf.insert( newNm.length()-newExt.length()-1 , sufix );
			newNm = buf.toString() ;
		}

		// 8.0.1.0 (2021/10/29) storageType , bucketName 削除
	//	File newFile = new File( dir,newNm );
//		final File newFile = HybsFileOperationFactory.create(storage, bucket, dir, newNm );	// 8.0.0.0
		final File newFile = HybsFileOperationFactory.create(useLocal, dir, newNm );	// 8.0.0.0

		// 5.10.9.0 (2019/03/01) MODIFY
		// File uniqFile = new File( dir , uniqKey );		// 5.7.1.1 (2013/12/13) ｱｯﾌﾟﾛｰﾄﾞされたﾌｧｲﾙ
//		final File uniqFile = HybsFileOperationFactory.create(storage, bucket, dir, uniqKey);
		final File uniqFile = HybsFileOperationFactory.create(useLocal, dir, uniqKey);

		// 5.10.9.0 (2019/03/01) MODIFY HybsFileUtilｸﾗｽの利用に変更｡
		FileUtil.renameTo( uniqFile , newFile, useBackup );		// from ⇒ to の順番に指定｡

		// (2017/09/22) ADD FILE型をString型に変更したので､getName()をfilenameに設定｡
		filename = newFile.getName();

	//	if( newNm != null && newNm.length() > 0 ) {
			// 5.9.25.0 (2017/10/06) ADD bluemixｸﾗｳﾄﾞｽﾄﾚｰｼﾞを利用する処理を追加
//			final String storage = HybsSystem.sys( "CLOUD_TARGET");
//			if(storage != null && storage.length() > 0){
//				// ｽﾄﾚｰｼﾞに保存
//				final StorageAPI storageApi = StorageAPIFactory.newStorageAPI(storage, HybsSystem.sys("CLOUD_BUCKET"), hsession);
//				storageApi.rename(fileURL, uniqKey, newNm, Boolean.valueOf( useBackup ), hsession);
//				// ﾌｧｲﾙ名をfilenameに設定する
//				filename = newNm;
//			} else {
//				// 標準のﾌｧｲﾙ作成
//	//			newFile = new File( dir,newNm );
//
//				final File uniqFile = new File( dir , uniqKey );		// 5.7.1.1 (2013/12/13) ｱｯﾌﾟﾛｰﾄﾞされたﾌｧｲﾙ
//
//				// 6.0.2.4 (2014/10/17) 戻り値は､変更後の新しい File ｵﾌﾞｼﾞｪｸﾄ
//				newFile = FileUtil.renameTo( uniqFile, newFile, useBackup );		// from ⇒ to の順番に指定｡
//
//				// 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた｡
//	//			FileUtil.renameTo( newFile, uniqFile , useBackup );
//	//			FileUtil.renameTo( uniqFile , newFile, useBackup );		// from ⇒ to の順番に指定｡
//				// (2017/09/22) ADD FILE型をString型に変更したので､getName()をfilenameに設定｡
//				filename = newFile.getName();
//			}
	//	}
	//	// 5.7.1.1 (2013/12/13) ここの処理が走ることは無いはず｡
	//	else {
	//		String errMsg = "新ﾌｧｲﾙ名が存在しません｡[" + newNm + "]" ;
	//		throw new RuntimeException( errMsg );
	//	}

			// 5.7.2.1 (2014/01/17) FileUtil.renameTo の引数の順番を間違えていた｡
			// 6.0.2.4 (2014/10/17) 戻り値は､変更後の新しい File ｵﾌﾞｼﾞｪｸﾄ
		// 新ﾌｧｲﾙ名のｾｯﾄは､すべての処理が完了してから､設定する｡
		// 5.9.25.0 (2017/10/06) DELETE FILE型をString型に変更により､前の処理でfinenameは設定済み
		return filename;
	}

	/**
	 * ﾌｧｲﾙ名(ｵﾘｼﾞﾅﾙ)を取得します｡
	 *
	 * @return	ﾌｧｲﾙ名(ｵﾘｼﾞﾅﾙ)
	 */
	public String getOriginalFileName() {
		return original;
	}

	/**
	 * 自然比較ﾒｿｯﾄﾞ
	 * ｲﾝﾀﾌｪｰｽ Comparable の 実装に関連して､再定義しています｡
	 * 登録されたｼｰｹﾝｽ(画面の表示順)で比較します｡
	 * equals ﾒｿｯﾄﾞでは､ｷｰの同一性のみに着目して判定しています｡
	 * この比較では､(運用上同一ｷｰは発生しませんが)たとえ同一ｷｰが存在した
	 * としても､その比較値が同じになることを保証していません｡
	 *
	 * @param   other 比較対象のObject
	 *
	 * @return  このｵﾌﾞｼﾞｪｸﾄが指定されたｵﾌﾞｼﾞｪｸﾄより小さい場合は負の整数､等しい場合はｾﾞﾛ､大きい場合は正の整数
	 * @throws  ClassCastException 引数が UploadedFile ではない場合
	 * @throws  IllegalArgumentException 引数が null の場合
	 */
	@Override	// Comparable
	public int compareTo( final UploadedFile other ) {
		if( other == null ) {
			final String errMsg = "引数が､null です｡" ;
			throw new IllegalArgumentException( errMsg );
		}

		return uniqKey.compareTo( other.uniqKey );
	}

	/**
	 * このｵﾌﾞｼﾞｪｸﾄと他のｵﾌﾞｼﾞｪｸﾄが等しいかどうかを示します｡
	 * 画面は､画面IDが等しければ､言語や表示順に関係なく同一とみなされます｡
	 * GUIInfo は､ﾕｰｻﾞｰ個別に扱われ､そのｸﾞﾙｰﾌﾟには､key は唯一で､かつ
	 * 同一言語内で扱われるｵﾌﾞｼﾞｪｸﾄの為､同一とみなします｡
	 *
	 * @param   object 比較対象の参照ｵﾌﾞｼﾞｪｸﾄ
	 *
	 * @return	引数に指定されたｵﾌﾞｼﾞｪｸﾄとこのｵﾌﾞｼﾞｪｸﾄが等しい場合は true､そうでない場合は false
	 */
	@Override
	public boolean equals( final Object object ) {
		// 6.4.1.1 (2016/01/16) PMD refactoring. A method should have only one exit point, and that should be the last statement in the method
		return object instanceof UploadedFile && uniqKey.equals( ((UploadedFile)object).uniqKey ) ;
	}

	/**
	 * ｵﾌﾞｼﾞｪｸﾄのﾊｯｼｭｺｰﾄﾞ値を返します｡
	 * このﾒｿｯﾄﾞは､java.util.Hashtable によって提供されるような
	 * ﾊｯｼｭﾃｰﾌﾞﾙで使用するために用意されています｡
	 * equals( Object ) ﾒｿｯﾄﾞをｵｰﾊﾞｰﾗｲﾄした場合は､hashCode() ﾒｿｯﾄﾞも
	 * 必ず 記述する必要があります｡
	 * この実装では､getKey().hashCode() と同値を返します｡
	 *
	 * @return  このｵﾌﾞｼﾞｪｸﾄのﾊｯｼｭｺｰﾄﾞ値
	 */
	@Override
	public int hashCode() {
		return uniqKey.hashCode() ;
	}

	/**
	 * ｵﾌﾞｼﾞｪｸﾄの識別子として，詳細な画面情報を返します｡
	 *
	 * @return  詳細な画面情報
	 * @og.rtnNotNull
	 */
	@Override
	public String toString() {
		final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE )
			.append( this.getClass().getName()			).append( CR )
			.append( "  uniqKey  :").append( uniqKey	).append( CR )
			.append( "  filename :").append( filename	).append( CR )
			.append( "  name     :").append( name		).append( CR )
			.append( "  dir      :").append( dir		).append( CR )
			.append( "  original :").append( original	).append( CR )
			.append( "  type     :").append( type		).append( CR );
		return rtn.toString();
	}
}
