/*
 * Aipo is a groupware program developed by Aimluck,Inc.
 * Copyright (C) 2004-2011 Aimluck,Inc.
 * http://www.aipo.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.aimluck.eip.common;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.jetspeed.om.security.Group;
import org.apache.jetspeed.services.JetspeedSecurity;
import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
import org.apache.jetspeed.services.logging.JetspeedLogger;

import com.aimluck.eip.cayenne.om.account.AvzMGroupsend;
import com.aimluck.eip.cayenne.om.account.AvzMGroupsendPosition;
import com.aimluck.eip.cayenne.om.account.AvzMPositionPosition;
import com.aimluck.eip.cayenne.om.account.AvzMRole;
import com.aimluck.eip.cayenne.om.account.EipMCompany;
import com.aimluck.eip.cayenne.om.account.EipMPosition;
import com.aimluck.eip.cayenne.om.account.EipMPost;
import com.aimluck.eip.orm.Database;
import com.aimluck.eip.util.ALEipUtils;

/**
 * 会社情報、部署情報、役職情報をメモリ上に保持するクラスです。 <br />
 * 
 */
public class ALEipManager {

  /** logger */
  private static final JetspeedLogger logger =
    JetspeedLogFactoryService.getLogger(ALEipManager.class.getName());

  /** Singleton */
  private static ALEipManager manager = new ALEipManager();

  /** 会社リスト */
  private final Map<String, Map<Integer, ALEipCompany>> companysMap =
    new LinkedHashMap<String, Map<Integer, ALEipCompany>>();

  /** 部署リスト */
  private final Map<String, Map<Integer, ALEipPost>> postsMap =
    new LinkedHashMap<String, Map<Integer, ALEipPost>>();

  /** 役職リスト */
  private final Map<String, Map<Integer, ALEipPosition>> positionsMap =
    new LinkedHashMap<String, Map<Integer, ALEipPosition>>();

  /** 役割リスト add start by motegi グループ送信対応 */
  private final Map<String, Map<Integer, ALEipRole>> rolesMap =
    new LinkedHashMap<String, Map<Integer, ALEipRole>>();

  /** グループ送信リスト add start by motegi グループ送信対応 */
  private final Map<String, Map<Integer, ALEipGroupSend>> groupsendsMap =
    new LinkedHashMap<String, Map<Integer, ALEipGroupSend>>();

  /**
   * 
   * 
   */
  private ALEipManager() {
    initCompany();
    initPost();
    initPosition();

    // add start by motegi グループ送信対応
    initRole();
    initGroupSend();
    // add end
  }

  /**
   * 
   * @return
   */
  public static ALEipManager getInstance() {
    return manager;
  }

  /**
   * 
   */
  private void initCompany() {
    companysMap.clear();
  }

  /**
   * 
   * 
   */
  private void initPost() {
    postsMap.clear();
  }

  /**
   * 
   * 
   */
  private void initPosition() {
    positionsMap.clear();
  }

  // add start by motegi グループ送信対応
  /**
   * セッションの役割情報をクリアする
   * 
   * @author motegi（グループ送信対応）
   */
  private void initRole() {
    rolesMap.clear();
  }

  /**
   * セッションのグループ送信情報をクリアする
   * 
   * @author motegi（グループ送信対応）
   */
  private void initGroupSend() {
    groupsendsMap.clear();
  }

  // add end

  /**
   * 
   */
  public void reloadCompany() {
    String orgId = Database.getDomainName();
    synchronized (companysMap) {
      try {
        List<EipMCompany> list = Database.query(EipMCompany.class).fetchList();
        Map<Integer, ALEipCompany> companyMap = companysMap.remove(orgId);
        if (companyMap == null) {
          companyMap = new LinkedHashMap<Integer, ALEipCompany>();
        } else {
          companyMap.clear();
        }
        for (EipMCompany record : list) {
          ALEipCompany company = new ALEipCompany();
          company.initField();
          company.setCompanyId(record.getCompanyId().intValue());
          company.setCompanyName(record.getCompanyName());
          companyMap.put(record.getCompanyId(), company);
        }

        companysMap.put(orgId, companyMap);
      } catch (Exception e) {
        logger.error("[" + orgId + ":ALEipManager]", e);
      }
    }
  }

  /**
   * @param orgId
   * 
   * 
   */
  public void reloadPost() {
    String orgId = Database.getDomainName();
    synchronized (postsMap) {
      try {

        List<EipMPost> list =
          Database.query(EipMPost.class).orderAscending(
            EipMPost.AVZ_MPOST_POSITION_ARRAY_PROPERTY
              + "."
              + AvzMPositionPosition.POSITION_PROPERTY).fetchList();
        // Collections.sort(list, new Comparator<EipMPost>() {
        // public int compare(EipMPost l1, EipMPost l2) {
        // return (l1).getPostName().compareTo((l2).getPostName());
        // }
        // });
        Map<Integer, ALEipPost> postMap = postsMap.remove(orgId);
        if (postMap == null) {
          postMap = new LinkedHashMap<Integer, ALEipPost>();
        } else {
          postMap.clear();
        }
        for (EipMPost record : list) {
          ALEipPost post = new ALEipPost();
          post.initField();
          post.setPostId(record.getPostId().intValue());
          post.setPostName(record.getPostName());
          post.setGroupName(record.getGroupName());
          // add by motegi start 部署階層化対応
          if (record.getParentPostId() != null) {
            post.setParentPostId(record.getParentPostId().intValue());
          }
          Group group = JetspeedSecurity.getGroup(record.getGroupName());
          post.setGroupId(Integer.parseInt(group.getId()));
          // add end
          postMap.put(record.getPostId(), post);
        }

        postsMap.put(orgId, postMap);
      } catch (Exception e) {
        logger.error("[" + orgId + ":ALEipManager]", e);
      }
    }
  }

  /**
   * @param orgId
   * 
   * 
   */
  public void reloadPosition() {
    String orgId = Database.getDomainName();
    synchronized (positionsMap) {
      try {
        List<EipMPosition> list =
          Database.query(EipMPosition.class).orderAscending(
            EipMPosition.AVZ_MPOSITION_POSITION_ARRAY_PROPERTY
              + "."
              + AvzMPositionPosition.POSITION_PROPERTY).fetchList();

        Map<Integer, ALEipPosition> positionMap = positionsMap.remove(orgId);
        if (positionMap == null) {
          positionMap = new LinkedHashMap<Integer, ALEipPosition>();
        } else {
          positionMap.clear();
        }
        for (EipMPosition record : list) {
          ALEipPosition position = new ALEipPosition();
          position.initField();
          position.setPositionId(record.getPositionId().intValue());
          position.setPositionName(record.getPositionName());
          positionMap.put(record.getPositionId(), position);
        }

        positionsMap.put(orgId, positionMap);
      } catch (Exception e) {
        logger.error("[" + orgId + ":ALEipManager]", e);
      }
    }
  }

  // add start by motegi グループ送信対応
  /**
   * 役割情報をセッションにリロードする
   * 
   * @author motegi（グループ送信対応）
   */
  public void reloadRole() {
    String orgId = Database.getDomainName();
    synchronized (rolesMap) {
      try {
        List<AvzMRole> list =
          Database.query(AvzMRole.class).orderAscending(
            AvzMRole.ROLE_NAME_PROPERTY).fetchList();

        Map<Integer, ALEipRole> roleMap = rolesMap.remove(orgId);
        if (roleMap == null) {
          roleMap = new LinkedHashMap<Integer, ALEipRole>();
        } else {
          roleMap.clear();
        }
        for (AvzMRole record : list) {
          ALEipRole role = new ALEipRole();
          role.initField();
          role.setRoleId(record.getRoleId().intValue());
          role.setRoleName(record.getRoleName());
          roleMap.put(record.getRoleId(), role);
        }

        rolesMap.put(orgId, roleMap);
      } catch (Exception e) {
        logger.error("[" + orgId + ":ALEipManager]", e);
      }
    }
  }

  /**
   * グループ送信情報をセッションにリロードする
   * 
   * @author motegi（グループ送信対応）
   */
  public void reloadGroupSend() {
    String orgId = Database.getDomainName();
    synchronized (groupsendsMap) {
      try {
        List<AvzMGroupsend> list =
          Database.query(AvzMGroupsend.class).orderAscending(
            AvzMGroupsend.AVZ_MGROUPSEND_POSITION_ARRAY_PROPERTY
              + "."
              + AvzMGroupsendPosition.POSITION_PROPERTY).fetchList();

        Map<Integer, ALEipGroupSend> groupsendMap = groupsendsMap.remove(orgId);
        if (groupsendMap == null) {
          groupsendMap = new LinkedHashMap<Integer, ALEipGroupSend>();
        } else {
          groupsendMap.clear();
        }
        for (AvzMGroupsend record : list) {
          ALEipGroupSend tmp = new ALEipGroupSend();
          tmp.initField();
          tmp.setGroupSendId(record.getGroupsendId());
          tmp.setGroupSendName(record.getGroupsendName());
          tmp.setGroupSendCode(record.getGroupsendCode());
          tmp.setCategory(record.getCategory());
          groupsendMap.put(record.getGroupsendId(), tmp);
        }

        groupsendsMap.put(orgId, groupsendMap);
      } catch (Exception e) {
        logger.error("[" + orgId + ":ALEipManager]", e);
      }
    }
  }

  // add end

  /**
   * 
   * @return
   */
  public Map<Integer, ALEipCompany> getCompanyMap() {
    synchronized (companysMap) {
      String orgId = Database.getDomainName();
      if (!companysMap.containsKey(orgId)) {
        reloadCompany();
        if (!companysMap.containsKey(orgId)) {
          return null;
        } else {
          return companysMap.get(orgId);
        }
      }
      return companysMap.get(orgId);
    }
  }

  /**
   * 
   * @return
   */
  public Map<Integer, ALEipPost> getPostMap() {
    synchronized (postsMap) {
      String orgId = Database.getDomainName();
      if (!postsMap.containsKey(orgId)) {
        reloadPost();
        if (!postsMap.containsKey(orgId)) {
          return null;
        } else {
          return postsMap.get(orgId);
        }
      }
      return postsMap.get(orgId);
    }
  }

  /**
   * 
   * @return
   */
  public Map<Integer, ALEipPosition> getPositionMap() {
    synchronized (positionsMap) {
      String orgId = Database.getDomainName();
      if (!positionsMap.containsKey(orgId)) {
        reloadPosition();
        if (!positionsMap.containsKey(orgId)) {
          return null;
        } else {
          return positionsMap.get(orgId);
        }
      }
      return positionsMap.get(orgId);
    }
  }

  // add start by motegi グループ送信対応
  /**
   * セッションから役割情報を取得します。
   * 
   * @author motegi（グループ送信対応）
   * @return 役割情報リスト
   */
  public Map<Integer, ALEipRole> getRoleMap() {
    synchronized (rolesMap) {
      String orgId = Database.getDomainName();
      if (!rolesMap.containsKey(orgId)) {
        reloadRole();
        if (!rolesMap.containsKey(orgId)) {
          return null;
        } else {
          return rolesMap.get(orgId);
        }
      }
      return rolesMap.get(orgId);
    }
  }

  /**
   * セッションからグループ送信情報を取得します。
   * 
   * @author motegi（グループ送信対応）
   * @return グループ送信情報リスト
   */
  public Map<Integer, ALEipGroupSend> getGroupSendsMap() {
    synchronized (groupsendsMap) {
      String orgId = Database.getDomainName();
      if (!groupsendsMap.containsKey(orgId)) {
        reloadGroupSend();
        if (!groupsendsMap.containsKey(orgId)) {
          return null;
        } else {
          return groupsendsMap.get(orgId);
        }
      }
      return groupsendsMap.get(orgId);
    }
  }

  // add end

  /**
   * セッションから部署1情報を取得します。
   * 
   * @author motegi（部署階層化対応）
   * @return 部署1情報リスト
   */
  // public Map<Integer, ALEipPost> getPost1Map() {
  public List<ALEipPost> getPost1Map() {
    final int POST1_PARENT_POST_ID = 0;
    return getPostMapsByParentPostId(POST1_PARENT_POST_ID);
  }

  /**
   * セッションから、部署1の部署IDをキーとして部署2情報を取得します。
   * 
   * @author motegi （部署階層化対応）
   * 
   * @param post1_id
   *            部署1の部署ID
   * @return 部署2情報リスト
   */
  // public Map<Integer, ALEipPost> getPost2Map(int post1_id) {
  public List<ALEipPost> getPost2Map(int post1_id) {
    return getPostMapsByParentPostId(post1_id);
  }

  /**
   * セッション、部署1のグループ名をキーとしてから部署2情報を取得します。
   * 
   * @author motegi （部署階層化対応）
   * 
   * @param post1_group_name
   *            部署1のグループ名
   * @return 部署2情報リスト
   */
  // public Map<Integer, ALEipPost> getPost2Map(String post1_group_name) {
  public List<ALEipPost> getPost2Map(String post1_group_name) {
    return getPostMapsByParentGroupName(post1_group_name);
  }

  /**
   * セッションから親部署IDをキーにして部署情報を取得します。
   * 
   * @author motegi （部署階層化対応）
   * @param post_id
   *            親部署ID
   * @return 部署情報リスト
   */
  // private Map<Integer, ALEipPost> getPostMapsByParentPostId(int post_id) {
  // Map<Integer, ALEipPost> map = ALEipManager.getInstance().getPostMap();
  // Map<Integer, ALEipPost> rtnMap = new LinkedHashMap<Integer, ALEipPost>();
  //
  // for (Iterator<ALEipPost> i = map.values().iterator(); i.hasNext();) {
  // ALEipPost al = i.next();
  // if (al.getParentPostId().getValue() == post_id) {
  // rtnMap.put((int) al.getPostId().getValue(), al);
  // }
  // }
  // return rtnMap;
  // }
  private List<ALEipPost> getPostMapsByParentPostId(int post_id) {
    Map<Integer, ALEipPost> map = ALEipManager.getInstance().getPostMap();
    List<ALEipPost> rtnMap = new ArrayList<ALEipPost>();

    for (Iterator<ALEipPost> i = map.values().iterator(); i.hasNext();) {
      ALEipPost al = i.next();
      if (al.getParentPostId().getValue() == post_id) {
        rtnMap.add(al);
      }
    }
    return rtnMap;
  }

  /**
   * セッションから親部署グループ名をキーにして部署情報を取得します。
   * 
   * @author motegi （部署階層化対応）
   * @param post_id
   *            親部署グループ名
   * @return 部署情報リスト
   */
  // public Map<Integer, ALEipPost> getPostMapsByParentGroupName(String
  // group_name) {
  public List<ALEipPost> getPostMapsByParentGroupName(String group_name) {
    int post1_id = (int) ALEipUtils.convertGroupName2GroupId(group_name);
    if (post1_id < 0) {
      return new ArrayList<ALEipPost>(0);
    }
    return getPostMapsByParentPostId(post1_id);
  }

  /**
   * セッションからグループ名をキーにして部署情報を取得します。
   * 
   * @author motegi （部署階層化対応）
   * @param post_id
   *            グループ名
   * @return 部署情報
   */
  public ALEipPost getPostMapByGroupName(String group_name) {
    ALEipPost rtn = null;
    Map<Integer, ALEipPost> map = ALEipManager.getInstance().getPostMap();

    for (Iterator<ALEipPost> i = map.values().iterator(); i.hasNext();) {
      ALEipPost al = i.next();
      if (group_name.equals(al.getGroupName().getValue())) {
        rtn = al;
      }
    }
    return rtn;
  }
}
