/**
 * Copyright (c) 2003-2004 System Integrator Corporation.
 *                 All Rights Reserved.
 */
package jp.co.sint.upload;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.ResourceBundle;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import jp.co.sint.config.SIConfig;
import jp.co.sint.config.SIDBMultiConf;
import jp.co.sint.database.SIDBAccessException;
import jp.co.sint.database.SIDuplicateKeyException;
import jp.co.sint.database.SIModifyRec;
import jp.co.sint.database.SISpcType;
import jp.co.sint.servlet.SIServlet;
import jp.co.sint.tools.SIBGPhotoTool;
import jp.co.sint.tools.SICheckUtil;
import jp.co.sint.tools.SIErrorFactory;
import jp.co.sint.tools.SIFileExistException;
import jp.co.sint.tools.SIUtil;

import org.apache.commons.fileupload.DefaultFileItem;
import org.apache.commons.fileupload.DeferredFileOutputStream;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.log4j.Category;

/**
 * @version $Id: SIUploadSrv.java,v 1.0 2003/12/04 Exp $
 * @author Jinwang Chen <br>
 *         Description:サーバーにファイルなどをアップロードすることを処理します。
 *         このクラスが、アップロードアプリケーション用のスーパークラスとして継承されるはずです。 設定パラメータ：
 *         <code>threshold</code> 数字 オプション <code>max</code> 数字 オプション
 *         <code>overwrite</code> true/false オプション <code>repository</code>
 *         フォルダ オプション <code>destPath</code> フォルダ オプション <code>delete</code>
 *         true/false オプション
 *         <p>
 *         History
 *         </p>
 *         <p>
 *         Author&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Date&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Reason
 *         </p>
 *         ============&nbsp;&nbsp;&nbsp;==========&nbsp;&nbsp;===========================
 *         <br>
 *         Jinwang Chen 2003/12/04 Original
 */
public class SIUploadSrv extends SIServlet {

  //ログ用のインスタンスの生成
  private static Category log = Category.getInstance(SIConfig.SILOG4J_WEBSHOP_CATEGORY_NAME);

  /**
   * <b>doUpdate </b> HTTP リクエストの処理
   * 
   * @param request
   *          リクエスト
   * @param response
   * @return なし
   * @throws ServletException
   * @throws IOException
   */
  public void doUpdate(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
  }

  /**
   * <b>doUpload </b> サーバーにファイルをアップロードします。
   * 
   * @param request
   *          リクエスト
   * @param response
   * @return なし
   * @throws ServletException
   * @throws IOException
   * @throws FileUploadException
   * @throws SIFileExistException
   */
  public void doUpload(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException, FileUploadException, SIFileExistException,
      FileNotFoundException {
    doUpload(request, response, new HashMap());
  }

  /**
   * <b>doUpload </b> サーバーにファイルをアップロードします。
   * 
   * @param request
   *          リクエスト
   * @param response
   * @param lparaMap
   * @throws ServletException
   * @throws IOException
   * @throws FileUploadException
   * @throws SIFileExistException
   */
  public void doUpload(HttpServletRequest request, HttpServletResponse response, HashMap lParaMap)
      throws ServletException, IOException, FileUploadException, SIFileExistException,
      FileNotFoundException {
    HashMap lMultiMap = new HashMap();
    String lResultMsg = "";
    HttpSession session = request.getSession();
    String lDestPath = "";
    String lDestFileName = "";
    boolean overwrite = true;
    File lFullDestFile = null;
    DiskFileUpload diskFile = new DiskFileUpload();
    DeferredFileOutputStream fileOutput;
    String lMapVal = "";
    boolean lIsValidFileName = true;

    //アップロード用のファイルリストのデータの取得
    DefaultFileItem[] fileItemList = (DefaultFileItem[]) (diskFile.parseRequest(request)
        .toArray(new DefaultFileItem[0]));
    for (int ii = 0; ii < fileItemList.length; ii++) {
      if (fileItemList[ii].isFormField()) {
        lMultiMap.put(fileItemList[ii].getFieldName(), fileItemList[ii].getString());
      }
    }

    //thresholdのデータの設定
    lMapVal = (String) lMultiMap.get("threshold");
    if (SIUtil.isNull(lMapVal))
      lMapVal = (String) lParaMap.get("threshold");
    if (SIUtil.isNull(lMapVal))
      lMapVal = getMapping("threshold");
    
    if (SIUtil.isNotNull(lMapVal)) {
      try {
        int sizeThreshold = Integer.parseInt(lMapVal);
        diskFile.setSizeThreshold(sizeThreshold);
      } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
      }
    }
    
    //maxのデータの設定
    lMapVal = (String) lMultiMap.get("max");
    if (SIUtil.isNull(lMapVal)) lMapVal = getMapping("max");
    if (SIUtil.isNull(lMapVal)) lMapVal = (String) lParaMap.get("max");
    if (SIUtil.isNotNull(lMapVal)) {
      try {
        long maxSize = Integer.parseInt(lMapVal);
        diskFile.setSizeMax(maxSize);
      } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
      }
    }
    
    //overwriteのデータの設定
    lMapVal = (String) lMultiMap.get("overwrite");
    if (SIUtil.isNull(lMapVal)) lMapVal = (String) lParaMap.get("overwrite");
    if (SIUtil.isNull(lMapVal)) lMapVal = getMapping("overwrite");
    if (SIUtil.isNotNull(lMapVal)) {
      try {
        overwrite = Boolean.valueOf(lMapVal).booleanValue();
      } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
      }
    }
    
    //repositoryのデータの設定
    lMapVal = (String) lMultiMap.get("repository");
    if (SIUtil.isNull(lMapVal))
      lMapVal = (String) lParaMap.get("repository");
    if (SIUtil.isNull(lMapVal))
      lMapVal = getMapping("repository");
    if (SIUtil.isNotNull(lMapVal)) {
      try {
        String repositoryPath = lMapVal;
        diskFile.setRepositoryPath(repositoryPath);
      } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
      }
    }
    
    //lDestPathのデータの設定
    lMapVal = (String) lMultiMap.get("destPath");
    if (SIUtil.isNull(lMapVal)) lMapVal = (String) lParaMap.get("destPath");
    if (SIUtil.isNull(lMapVal)) lMapVal = getMapping("destPath");
    lDestPath = lMapVal;
    
    lMapVal = (String) lMultiMap.get("destFile");
    if (SIUtil.isNull(lMapVal)) lMapVal = (String) lParaMap.get("destFile");
    if (SIUtil.isNull(lMapVal)) lMapVal = getMapping("destFile");
    lDestFileName = lMapVal;
    
    //ショップロゴ画像以外のときsubDirを設定（ショップロゴ画像のときはimageフォルダの直下に保存する）
    if (!lDestPath.equalsIgnoreCase(SIConfig.SISITELOGO_FOLDER_NAME)) {
      lMapVal = (String) lMultiMap.get("subDir");
    }
    if (SIUtil.isNull(lMapVal)) lMapVal = (String) lParaMap.get("destFile");
    if (SIUtil.isNull(lMapVal)) lMapVal = getMapping("destFile");
    if (SIUtil.isNotNull(lMapVal)) lDestPath = lDestPath + lMapVal + "/";
    createFolder(lDestPath);
    
    try {
      for (int ii = 0; ii < fileItemList.length; ii++) {
        if (!fileItemList[ii].isFormField()) {//アップロードファイルの項目であれば
          if (SIUtil.isNull(lDestFileName)) {
            lFullDestFile = getAbsFileName(lDestPath, (new File(fileItemList[ii].getName())
                .getName()));
            log.debug("fileItemList[ii].getName()=" + fileItemList[ii].getName());
          } else {
            lDestFileName = SIUtil.getOsFileName(lDestFileName);
            lFullDestFile = new File(lDestFileName);
          }
          if (!overwrite && lFullDestFile.exists()) {
            throw new SIFileExistException("File " + lFullDestFile.getAbsolutePath() + " exist!");
          }
          if (SICheckUtil.isAlphaDigit(lFullDestFile.getName())) {
            fileItemList[ii].write(lFullDestFile);//実行
          } else {
            lIsValidFileName = false;
          }
          //ファイルのサイズが0であれば削除してエラーを表示
          if (lIsValidFileName && lFullDestFile.length() == 0) {
            lFullDestFile.delete();
            session.setAttribute(SIConfig.SISESSION_UPLOAD_NAME, lMultiMap);
            throw new FileNotFoundException();
          }
        }
      }
      //
    } catch (FileNotFoundException e) {
      throw new FileNotFoundException();
    } catch (FileUploadException e) {
      throw new FileUploadException();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      session.setAttribute(SIConfig.SISESSION_UPLOAD_NAME, lMultiMap);
    }
    
    //解凍
    boolean lExtractEnable = false;
    String lExtract = getMultiParameter(request, "extractChk");
    
    if (SIUtil.isNull(lExtract)) {
      lExtractEnable = false;
    } else if (lExtract.equalsIgnoreCase("YES") || lExtract.equalsIgnoreCase("TRUE")
            || lExtract.equalsIgnoreCase("1")   || lExtract.equalsIgnoreCase("ON")) {
      lExtractEnable = true;
    }
    log.debug("lExtract=" + lExtract + ",lExtractEnable=" + lExtractEnable);
    
    if (!lIsValidFileName) {
      request.setAttribute(SIConfig.SIMESSAGE_ATTRIBUTE_RESULT_NAME, SIErrorFactory.getErrorMsg(
          "input.data.alphadigit", "画像ファイル"));//7.1.1 ST0162 修正
      return;
    }
    
    if (lExtractEnable) {
      //解凍の実行
      boolean lRes = SIUtil.extractFile(lFullDestFile, getAbsFileName(lDestPath, "/"));
      
      if (lRes)
        request.setAttribute(SIConfig.SIMESSAGE_ATTRIBUTE_RESULT_NAME, SIErrorFactory
            .getErrorMsg("manager.message.success.extract"));
      else
        request.setAttribute(SIConfig.SIMESSAGE_ATTRIBUTE_RESULT_NAME, SIErrorFactory
            .getErrorMsg("manager.message.failure.extract"));
      //削除
      String lDel = (String) getMapping("delete");
      lRes = lRes && (SIUtil.isNull(lDel) || lDel.equalsIgnoreCase("TRUE") || lDel.equalsIgnoreCase("YES")
                                          || lDel.equalsIgnoreCase("1")    || lExtract.equalsIgnoreCase("ON"));
      if (lRes)
        lFullDestFile.delete();
    }
  }
  
  /**
   * <b>getMultiParameter </b> ファイルをアップロードするフォームに、ほかの項目に対する値を取得します。
   * 
   * @param request
   *          リクエスト
   * @param lName
   *          対象項目
   * @return 対象項目のデータ
   * @throws なし
   */
  public String getMultiParameter(HttpServletRequest request, String lName) {
    HttpSession session = request.getSession();
    HashMap lMultiMap = (HashMap) session.getAttribute(SIConfig.SISESSION_UPLOAD_NAME);
    if (lMultiMap == null) return "";
    Object lValue = lMultiMap.get(lName);
    
    //パラメータのデータ
    if (lValue == null) {
      return "";
    } else if (lValue instanceof String) {
      return (String) lValue;
    } else {
      log.warn("not string!!!!");
      return "";
    }
  }

  /**
   * <b>getAbsFileName </b> アップロード先に目的ファイル名を生成します。
   * 
   * @param lDestPath
   *          アップロード先のパス
   * @param lDestFileName
   *          目的ファイル
   * @return 目的ファイルのオブジェクト
   * @throws なし
   */
  private File getAbsFileName(String lDestPath, String lDestFileName) {
    lDestPath = SIUtil.getOsFileName(lDestPath);
    lDestFileName = SIUtil.getOsFileName(lDestFileName);
    if (!SIConfig.SIOS_CURRENT_NAME.equals(SIConfig.SIOS_WINDOW_SERIES_NAME) && SIUtil.isNotNull(lDestFileName)) {
      int ii = lDestFileName.lastIndexOf("/");
      if (ii > 0) lDestFileName = lDestFileName.substring(ii + 1);
    }
    
    File lResFile = new File(lDestPath, lDestFileName);
    if (lResFile.isAbsolute()) return lResFile;
    return new File(getServletContext().getRealPath(lDestPath), lDestFileName);
  }
  
  /**
   * <b>getAbsFileName </b> 目的フォルダを生成します。
   * 
   * @param lFolderName
   * @return なし
   * @throws なし
   */
  private void createFolder(String lFolderName) {
    log.debug("createFolder:lFolderName=" + lFolderName);
    String lAbsPath = getServletContext().getRealPath(lFolderName);
    File lFile = new File(lAbsPath);
    lFile.mkdirs();
  }
  
  /**
   * <b>doUpload </b> サーバーにファイルをアップロードします。
   * 
   * @param request リクエスト
   * @param response
   * @param lparaMap
   * @throws ServletException
   * @throws IOException
   * @throws FileUploadException
   * @throws SIFileExistException
   */
  public void doUploadBG(HttpServletRequest request, HttpServletResponse response,HashMap lParaMap, Connection conn)
      throws ServletException, IOException, FileUploadException, SIFileExistException, FileNotFoundException {
    HashMap lMultiMap = new HashMap();
    HttpSession session = request.getSession();
    String lDestPath = "";
    String lDestFileName = "";
    boolean overwrite = true;
    File lFullDestFile = null;
    DiskFileUpload diskFile = new DiskFileUpload();
    String lMapVal = "";
    boolean lIsValidFileName = true;
    
    //serverの文字コード設定
    ResourceBundle rb = ResourceBundle.getBundle(SIConfig.SICONFIG_ENCODING_FILE_NAME);
    String clientCode = rb.getString("clientCode");
    //アップロード用のファイルリストのデータの取得
    DefaultFileItem[] fileItemList = (DefaultFileItem[]) (diskFile.parseRequest(request).toArray(new DefaultFileItem[0]));
    
    for (int ii = 0; ii < fileItemList.length; ii++) {
      if (fileItemList[ii].isFormField()) {
        byte tempByte[] = fileItemList[ii].get();
        String str = new String(tempByte, clientCode);
        lMultiMap.put(fileItemList[ii].getFieldName(), str);
      }
    }
    
    // thresholdのデータの設定
    lMapVal = (String) lMultiMap.get("threshold");
    if (SIUtil.isNull(lMapVal)) lMapVal = (String) lParaMap.get("threshold");
    if (SIUtil.isNull(lMapVal)) lMapVal = getMapping("threshold");
    
    if (SIUtil.isNotNull(lMapVal)) {
      try {
        int sizeThreshold = Integer.parseInt(lMapVal);
        diskFile.setSizeThreshold(sizeThreshold);
      } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
      }
    }
    
    //maxのデータの設定
    lMapVal = (String) lMultiMap.get("max");
    if (SIUtil.isNull(lMapVal)) lMapVal = getMapping("max");
    if (SIUtil.isNull(lMapVal)) lMapVal = (String) lParaMap.get("max");
    if (SIUtil.isNotNull(lMapVal)) {
      try {
        long maxSize = Integer.parseInt(lMapVal);
        diskFile.setSizeMax(maxSize);
      } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
      }
    }
    
    //overwriteのデータの設定
    lMapVal = (String) lMultiMap.get("overwrite");
    if (SIUtil.isNull(lMapVal))
      lMapVal = (String) lParaMap.get("overwrite");
    if (SIUtil.isNull(lMapVal))
      lMapVal = getMapping("overwrite");
    if (SIUtil.isNotNull(lMapVal)) {
      try {
        overwrite = Boolean.valueOf(lMapVal).booleanValue();
      } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
      }
    }
    
    //repositoryのデータの設定
    lMapVal = (String) lMultiMap.get("repository");
    if (SIUtil.isNull(lMapVal))
      lMapVal = (String) lParaMap.get("repository");
    if (SIUtil.isNull(lMapVal))
      lMapVal = getMapping("repository");
    if (SIUtil.isNotNull(lMapVal)) {
      try {
        String repositoryPath = lMapVal;
        diskFile.setRepositoryPath(repositoryPath);
      } catch (Exception e) {
        log.error(e);
        e.printStackTrace();
      }
    }
    
    String action         = (String) lMultiMap.get("actionNameTxt");
    String shopCode       = (String) lMultiMap.get("shopCode");
    String cmdtyCode      = (String) lMultiMap.get("cmdtyCode");
    String individualCode = (String) lMultiMap.get("individualCode");
    String imageNo        = (String) lMultiMap.get("imageNoTxt");
    String imageName      = (String) lMultiMap.get("imageName"+imageNo);
    
    //lDestPathのデータの設定
    lDestPath=SIConfig.SIUPLOAD_FOLDER[0]+cmdtyCode+"/";
    createFolder(lDestPath);
    
    if (action.equals(SIConfig.SIACTION_UPLOAD)) {
      if(imageName.equals("")) throw new FileNotFoundException();
      
      try {
        updateTableDataImage(conn,shopCode,cmdtyCode,individualCode,imageName,imageNo);
      } catch (SIDBAccessException e) {
        e.printStackTrace();
        try {
          conn.rollback();
        } catch (SQLException se) {}
      }
      try {
        for (int ii = 0; ii < fileItemList.length; ii++) {
          if (fileItemList[ii].getFieldName().equals("filedata"+imageNo)){
            if (!fileItemList[ii].isFormField()) {//アップロードファイルの項目であれば
              if (SIUtil.isNull(lDestFileName)) {
                lFullDestFile = getAbsFileName(lDestPath,cmdtyCode+"_"+individualCode+"_"+imageNo+".jpg");
                log.debug("fileItemList[ii].getName()="+fileItemList[ii].getName());
              } else {
                lDestFileName = SIUtil.getOsFileName(lDestFileName);
                lFullDestFile = new File(lDestFileName);
              }
              if (!overwrite && lFullDestFile.exists()) {
                throw new SIFileExistException("File "+lFullDestFile.getAbsolutePath()+" exist!");
              }
              if (SICheckUtil.isAlphaDigit(lFullDestFile.getName())) {
                if(SIUtil.isNotNull(fileItemList[ii].getName())){
                  fileItemList[ii].write(lFullDestFile);//実行
                  if ("1".equals(imageNo)){
                    File newFile1 = getAbsFileName(lDestPath,cmdtyCode+"_"+individualCode+"_t.jpg");
                    SIBGPhotoTool tool1 = new SIBGPhotoTool(lFullDestFile,newFile1,100,75,0);
                    tool1.execute();
                    
                    File newFile2 = getAbsFileName(lDestPath,"mobile_"+cmdtyCode+"_"+individualCode+"_t.jpg");
                    SIBGPhotoTool tool2 = new SIBGPhotoTool(lFullDestFile,newFile2,100,75,2048);
                    tool2.execute();
                    
                    File newFile3 = getAbsFileName(lDestPath,"mobile_"+cmdtyCode+"_"+individualCode+"_1.jpg");
                    SIBGPhotoTool tool3 = new SIBGPhotoTool(lFullDestFile,newFile3,240,180,8192);
                    tool3.execute();
                  }else{
                    File newFile = getAbsFileName(lDestPath,"mobile_"+cmdtyCode+"_"+individualCode+"_"+imageNo+".jpg");
                    SIBGPhotoTool tool = new SIBGPhotoTool(lFullDestFile,newFile,240,180,8192);
                    tool.execute();
                  }
                }
              } else {
                lIsValidFileName = false;
              }
              //ファイルのサイズが0であれば削除してエラーを表示
              if (lIsValidFileName && lFullDestFile.length() == 0) {
                lFullDestFile.delete();
                session.setAttribute(SIConfig.SISESSION_UPLOAD_NAME, lMultiMap);
                throw new FileNotFoundException();
              }
            }
          }
        }
      } catch (FileNotFoundException e) {
        try {
          conn.rollback();
        } catch (SQLException se) {}
        throw new FileNotFoundException();
      } catch (FileUploadException e) {
        try {
          conn.rollback();
        } catch (SQLException se) {}
        throw new FileUploadException();
      } catch (Exception e) {
        try {
          conn.rollback();
        } catch (SQLException se) {}
        e.printStackTrace();
      } finally {
        session.setAttribute(SIConfig.SISESSION_UPLOAD_NAME, lMultiMap);
      }
    } else {
      try {
        updateTableDataImage(conn,shopCode,cmdtyCode,individualCode,"",imageNo);
      } catch (SIDBAccessException e) {
        e.printStackTrace();
        try {
          conn.rollback();
        } catch (SQLException se) {}
      }
      lFullDestFile = getAbsFileName(lDestPath,cmdtyCode+"_"+individualCode+"_"+imageNo+".jpg");
      lFullDestFile.delete();
    }
    try {conn.commit();}catch (SQLException sqle) {}
    
  }
  
  /**
   * <b>updateTableDataImage </b> データベースにレコードを修正します。
   * 
   * @param lConnection DBへのコネクション
   * @param individual 入力したデータ
   * @param imageNo 対象の画像番号
   * @return なし
   * @throws SIDuplicateKeyException
   * @throws SIDBAccessException
   */
  public static void updateTableDataImage(Connection lConnection, String shopCode, String cmdtyCode, String individualCode, String imageName, String imageNo) throws SIDBAccessException {
    SIModifyRec lRec = new SIModifyRec("individualtbl");
    
    try {
      lRec.addCondition("shopCode", shopCode);
      lRec.addCondition("cmdtyCode", cmdtyCode);//
      lRec.addCondition("individualCode", individualCode);//
      lRec.add("imageName" + imageNo, imageName);//
      
      SISpcType lSpcType = new SISpcType();
      lSpcType = new SISpcType("TO_CHAR(now(),'YYYY/MM/DD HH24:MI:SS')::timestamp");
      lRec.add("InitDateTime", lSpcType);//登録日時
      //商品マスタの更新
      lRec.execute(lConnection);
      
      if (imageNo.equals("1")) {
        lRec.add("imageNamet", "サムネイル");
        lRec.execute(lConnection);
      }
      
    } catch (SIDuplicateKeyException sqle) {
      throw new SIDBAccessException(sqle);
    }
  }

}