# -*- coding: utf-8 -*-
#
#= 表示名取得共通
# Authors:: Sumiyo Yamamoto
# Copyright:: Copyright (C) OrbusNeich Medical K.K.  2010.
#--
# date        name                   note
# 2010.2.19   Sumiyo Yamamoto        新規作成
#-------------------------------------------------------------------------------
#++
module Comm
  module Tool
    #= 表示名取得汎用機能クラス
    # 汎用的に使えるメソッド群を備える。
    #------------------------------------------------------------------------#++
    class DispName
      extend Comm::Const::DispName
      extend App::Const::DispName
      extend Comm::Const::MasterCode
    end

    class << DispName
      DISP_KEY_STR = 'disp_name'
      REGEX_ID = Regexp.new('(.+)_id$')
      REGEX_CODE = Regexp.new('(.+)_code$')
      #== 表示名一覧取得(ID)
      #_col_name_:: カラム名 (ex. user_id)
      #_req_cols_:: 表示名disp_name以外に追加取得するカラム名
      #_master_find_opt_:: マスターの検索オプション
      #_ids_:: 取得するレコードのID（空の場合は全取得）
      #
      # 戻り値:: 表示名データ配列
      #-----------------------------------------------------------------#++
      GET_ID_BASE_KEYS_STR = "id, invalid_flag_code as ivf "
      MASTER_TABLES = Comm::BaseModel::Master.connection.tables
      def get_id_disp_names(col_name = nil, req_cols = [], master_find_opt = nil, ids = [], disp_key = DISP_KEY_STR, sort_opt = nil)
        #--------------#
        # クラス名編集 #
        #--------------#++
        # (_id)の前がテーブル名でない特殊なカラム名(共通)
        if cls = PARTICULAR_COL_INFO[col_name]
        # (_id)の前がテーブル名でない特殊なカラム名(アプリ固有)
        elsif cls = APP_PARTICULAR_COL_INFO[col_name]
        # (_id)の前がテーブル名であるカラム名
        else
          REGEX_ID =~ col_name
          table_name = $1.pluralize
          #マスターでなければ返す
          unless MASTER_TABLES.include?(table_name)
            return []
          end
          cls = table_name.classify
        end
        #--------------#
        # 検索         #
        #--------------#++
        #invalid_flag_code=1の物がでてこないので。。code masterではinvalid_flag_code=0のみ
        #opt = (['id', 'disp_name'] + req_cols).join(',')
        #cmd = cls + ".set(master_find_opt).passign('id', ids).find(:all, :select => opt, :order => 'disp_sort')"
        # select
        opt = GET_ID_BASE_KEYS_STR + ',' + disp_key
        if req_cols.length > 0
          opt = req_cols.join(',').insert(0, ',').insert(0, opt)
        end
        
        # condition
        #上記invalid_flag_code=1の物がでてこないので...を考慮してmaster_find_optは無視しています。
        #考慮する場合はcondsに工夫しましょう。
        conds = []
        if ids.length > 0
          conds << "id IN (#{ids.join(',')})"
        end
        case master_find_opt
        when MFIND_V
          conds << "(invalid_flag_code = #{MCODE_FLAG_OFF})"
        when MFIND_I
          conds << "(invalid_flag_code = #{MCODE_FLAG_ON})" 
        end
        clso = eval(cls)
        ars = clso.find(:all,
                        :select => opt,
                        :conditions => conds.join(' AND '),
                        :order => sort_opt.blank? ? 'disp_sort IS NULL ASC, disp_sort ASC, id ASC' : (sort_opt + ' ASC') )
        return ars.only_hashfy
      rescue Exception => e
        Rails.logger.info("Exception @ get_id_disp_names: " + e.message.inspect)
        Rails.logger.debug("Exception @ get_id_disp_names: " + e.backtrace.join("\n"))
        return []
      end

      #== 表示名一覧取得(コード)
      #_col_name_:: カラム名 (ex. visit_type_code)
      #_req_cols_:: 表示名disp_name以外に追加取得するカラム名
      #_master_find_opt_:: マスターの検索オプション
      #_ids_:: 取得するレコードのコード番号（空の場合は全取得）
      #
      # 戻り値:: 表示名データ配列
      #-----------------------------------------------------------------#++
      GET_CODE_BASE_KEYS_STR = "code_number id"
      def get_code_disp_names(col_name = nil, req_cols = [], master_find_opt = nil, ids = [], disp_key = DISP_KEY_STR)
        # code_type_id値取得（共通）
        if type_id = CODE_MASTER_TYPE_INFO[col_name]
        # code_type_id値取得（アプリ固有）
        elsif APP_CODE_MASTER_TYPE_INFO
          type_id = APP_CODE_MASTER_TYPE_INFO[col_name]
        end
        unless type_id
          return []
        end
        
        # 検索
        #opt = (['code_number id', 'disp_name'].concat(req_cols)).join(',')
        opt = GET_CODE_BASE_KEYS_STR + ',' + disp_key
        if req_cols.length > 0
          opt = req_cols.join(',').insert(0, ',').insert(0, opt)
        end
        # condition
        conds = ["(code_type_id = #{type_id})"]
        if ids.length > 0
          conds << "code_number IN (#{ids.join(',')})"
#          condition_array = []
#          ids.each do |val|
#            condition_array.push("code_type_id LIKE '%#{val}%'")
#          end
#          conds << "(#{condition_array.join(' OR ')})"
        end
        case master_find_opt
        when MFIND_V
          conds << "(invalid_flag_code = #{MCODE_FLAG_OFF})"
        when MFIND_I
          conds << "(invalid_flag_code = #{MCODE_FLAG_ON})" 
        end
        #ars = CodeMaster.set(master_find_opt).sassign('code_type_id', type_id).passign('code_number', ids).dsort.find(:all, :select => opt)
        ars = CodeMaster.find(:all,
                              :select => opt,
                              :conditions => conds.join(' AND '),
                              :order => 'disp_sort IS NULL ASC, disp_sort ASC, id ASC')
        return ars.only_hashfy
      rescue Exception => e
        Rails.logger.info("Exception @ get_code_disp_names " + e.message.inspect)
        Rails.logger.debug("Exception @ get_code_disp_names " + e.backtrace.join("\n"))
        return []
      end
      
      #== 表示名追加実行
      #_targets_:: 追加対象
      #_col_name_:: カラム名 (ex. user_id, visit_type_code)
      #_req_cols_:: 追加カラム
      #
      # 戻り値:: self
      #-----------------------------------------------------------------#++
      DN_STR = '_dn'
      UB_STR = '_'
      def add_disp_name(targets = [], col_name = nil, req_cols = [], opts = {})
        # 検索ID or コード番号リスト編集
        #ids = (targets.map {|r| r[col_name] }).delete_if {|r| r.blank? }.uniq
        # 表示名の追加が必要なカラム(id)
        disp_key = opts[:disp_key] || DISP_KEY_STR
        if REGEX_ID =~ col_name
          master_name = $1
          ids = get_target_ids(targets, col_name)
          disp_names = Comm::Tool::DispName.get_id_disp_names(col_name, req_cols, MFIND_A, ids, disp_key)
        # 表示名の追加が必要なカラム(code)
        elsif REGEX_CODE =~ col_name
          master_name = $1
          ids = get_target_ids(targets, col_name)
          disp_names = Comm::Tool::DispName.get_code_disp_names(col_name, req_cols, MFIND_A, ids, disp_key)
        else
          return targets
        end
        nil_str = opts[:nil_str] ? opts[:nil_str] : ''
        add_col_name = master_name + DN_STR
        master_head = master_name + UB_STR
        if opts[:multiple_id_col] #カンマ区切りで複数のIDを持つようなカラム string型である
          targets.each do |r|
            if r[col_name].blank?
              r[add_col_name] = nil_str
            else
              vals = r[col_name].to_s.split(",")
              disp_vals = []
              vals.each do |v|
                idx = search_disp_name(v.to_i, disp_names)
                unless idx.nil?
                  disp_vals.push(disp_names[idx][disp_key])
                end
              end
              r[add_col_name] = disp_vals.join(",")
            end
          end
        else
          targets.each do |r|
            val = r[col_name].nil? ? nil : r[col_name].to_i
            idx = search_disp_name(val, disp_names)
            if idx.nil?
              r[add_col_name] = nil_str
              # 追加カラム
              req_cols.each do |req_col|
                r[master_head + req_col] = nil_str
              end
            else
              r[add_col_name] = disp_names[idx][disp_key]
              # 追加カラム
              req_cols.each do |req_col|
                r[master_head + req_col] = disp_names[idx][req_col]
              end
            end
          end
        end
        return targets
      end
      
      def add_disp_name_unit(target = {}, col_name = nil, req_cols = [], opts = {})
        targets = add_disp_name([target], col_name, req_cols, opts)
        return targets[0]
      end
      
      # 検索ID or コード番号リスト取得
      def get_target_ids(targets, col_name)
        ids=[]
        targets.each do |r|
          rcol = r[col_name]
          if !rcol.blank? and !ids.include?(rcol)
            ids << rcol
          end
        end
        return ids
      end
      #== 表示名検索
      #_val_:: 検索値
      #_disp_names_:: 表示名リスト
      #
      # 戻り値:: 検索結果（インデックス値）
      #-----------------------------------------------------------------#++
      ID_STR='id'
      def search_disp_name(val = nil, disp_names = [])
        # 検索値が空の場合は、nilを返す
        unless val
          return nil
        end
        # リストが空の場合は、nilを返す
        if disp_names.length <= 0
          return nil
        end
        # 検索実行
        disp_names.each_with_index do |r, idx|
          if r[ID_STR] == val
             return idx
          end
        end
        return nil
      end
    end
  end
end
