#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
ElementContainerArray の領域切り取りと積算処理
"""
import os
import sys
## [KCS 130520]-->
#import Manyo
import Manyo.Utsusemi as mu
## <-- [KCS 130520]

#######################################
#  M2Clip
####################################### 
class M2Clip(object) :
    """
    ElementContainerArray の指定領域を切り取って積算し、ヒストグラムを作成
    """
    #########################################
    def __init__(self,eca):
        """ 
        コンストラクタ
        @param  eca  エレメントコンテナアレイまたはマトリックスのポインタ
        @retval 無し
        """ 
        #<-- 2013.06.26 KCS Bug Fix
        self._eca = eca      # マスククリア時に初期化するために保存
        self._mask = False   # マスク設定フラグ
        #--> 2013.06.26 KCS Bug Fix
        self._mode = 0           # デフォルトで積算指定
        self._axis = 0           # デフォルトで、TOF または Energy 指定
        self._region = None      # 最後に設定した切り取り領域
        self._d2c = None         # Manyo Lib 内のD2Clip のインスタンス
        self._resultArray = None # 計算結果格納用
        
        self._freecut_width = 0
        self._freecut_bin = 0

        # データ読み込み
        try:
            ## [KCS 130520]-->
            #self._d2c = Manyo.DataClip(eca)
            self._d2c = mu.UtsusemiEcsClipper(eca)
            ## <-- [KCS 130520]
        except:
            # ManyoLib データ読み出し時に例外発生(不当なデータ)
            print "Invalid Data!!"
            return
        
        # 正常なデータでなければ
        if (self._d2c.IsInvalid()):
            self._d2c = None;
            print "Invalid Data bb!!"
        else:
            print "Data is OK."
    
    ## [KCS 130520]-->        
    ######################################### 
    def IsInvalid(self): 
        """
        不正データか
        @param  無し
        @retval True: Invalid, False : valid
        """    
        return self._d2c.IsInvalid()
    ## <-- [KCS 130520]
    
    ######################################### 
    def ClearMask(self): 
        """
        除外領域をクリア
        @param  無し
        @retval 無し
        """ 
        #<-- 2013.06.26 KCS Bug Fix   
        #if self._d2c != None:
            #self._d2c.ClearMask()  
        if self._d2c != None and self._mask:
            del self._d2c
            self._mask = False
            self._d2c = mu.UtsusemiEcsClipper(self._eca)
        #--> 2013.06.26 KCS Bug Fix

    ######################################### 
    def SetMask(self, *args): 
        """
        計算
        @param  fname  マスクファイル名称
        @retval 無し
        """    
        if self._d2c == None:
            return
        
        # 文字列か(ファイル名か)
        if isinstance(args[0], str):
            # ファイルを開く
            fr = open(args[0], 'r')
            if fr == None:
                print "Cant opene the file." 
                return
            # 1行づつ読み込む
            for line in fr:
                items = line[:-1].split(',')
                # 1行に4個のデータがあるか
                if(len(items) < 4):
                    print "Invalid mask file."
                    return

                # 整合性チェック
                if self._CheckRegion(items):
                    self._mask = True   #debug
                    self._d2c.SetMask(items[0], items[1], items[2], items[3])
                else:
                    return
        
        # 数値4個の設定か
        elif (len(args) == 4):
            items = [args[0], args[1],args[2],args[3]]
            # 整合性チェック
            if self._CheckRegion(items):
                self._mask = True   #debug
                self._d2c.SetMask(items[0], items[1], items[2], items[3])
        
        # 引数の数をチェック
        else:
            print "Number of arguments must be 1 or 4."


    ######################################### 
    def SetAxis(self, axis, width=0, vbin=0): 
        """
        ヒストグラムのX軸を指定
        @param  axis 0: TOF or Energy, 1: Index or Q
        @retval 無し
        """    
        if self._d2c == None:
            return
        
        if axis == 0 or axis == 1:
            self._axis = axis
            self._freecut_width = 0
            self._freecut_bin = 0
        elif axis == 2:
            self._axis = axis
            self._freecut_width = width
            self._freecut_bin = vbin
        else:
            print "axis must be 0 or 1." 
            
    ######################################### 
    def SetMode(self, mode): 
        """
        計算方式指定
        @param  mode 0: 平均値, 1: 加算
        @retval 無し
        """    
        if self._d2c == None:
            return
        
        if mode == 0 or mode == 1:
            self._mode = mode
        else:
            print "mode must be 0 or 1."   
            
    ######################################### 
    def SetClipRegion(self, x0, y0, x1, y1): 
        """
        計算方式指定
        @param  x0 : Index または Q の始値
        @param  y0 : TOF または Energy の始値
        @param  x1 : Index または Q の終値
        @param  y1 : TOF または Energy の終値
        @retval 無し
        """    
        if self._d2c == None:
            print "Invalid Data cc!!"
            return
        
        items = [x0, y0, x1, y1]
        # 整合性チェック
        if self._CheckRegion(items):
            # D2Clip に設定
            self._d2c.SetClipRegion(items[0], items[1], items[2], items[3])
            # Shift のために、値を保存
            self._region = items 
        else:
            print "Argument Error!!" 
            
    ######################################### 
    def ClearClipRegion(self): 
        """
        切り取り領域をクリア
        @param  無し
        @retval 無し
        """    
        if self._d2c == None:
            return
        self._d2c.ClearClipRegion() 
        self._region = None
        self._resultArray = None
                                   
    ######################################### 
    def ShiftClipSteps(self, xdiff, ydiff, steps): 
        """
        切り取り領域をクリア
        @param  xdiff  Index または Q 遷移量
        @param  ydiff  TOF または Energy 遷移量
        @param  steps  ステップ数
        @retval 無し
        """    
        if self._d2c == None:
            return
        
        # 先に SetClipRegion を実行しているか
        if self._region == None:
            print "Commit SetClipRange first."
            return
        
        # 引数の型チェック
        if not isinstance(steps, int):
            print "steps must be integer."
            return
        
        try:
            xdif = self._ConvertToDouble(xdiff) 
        except:
            print "xdiff must be numeric."
            return
        
        try:
            ydif = self._ConvertToDouble(ydiff) 
        except:
            print "ydiff must be numeric."
            return
        
        # 指定されたステップ数分繰り返す
        for i in range(steps):
            self._region[0] += xdiff
            self._region[1] += ydiff
            self._region[2] += xdiff
            self._region[3] += ydiff
            
            # D2Clip に設定
            self._d2c.SetClipRegion(self._region[0], self._region[1], self._region[2], self._region[3])

    ######################################### 
    def ExecClip(self): 
        """
        積算の実行
        @param  無し
        @retval 無し
        """ 
        # 切り取り領域が指定されているか
        if self._region == None:
            print "There is no region to clip."
            return 
        average = True
        if self._mode == 1:
            average = False
            
        self._resultArray = self._d2c.ExecInteg(average, self._axis, self._freecut_width, self._freecut_bin)
                     
    ######################################### 
    def GetEC(self, index = 0): 
        """
        結果取得(ElementContainer)
        @param  Index 結果の順番
        @retval ElementContainer
        """ 
        # 結果があるか
        if self._resultArray == None:
            print "There is no result."
            return 
        
        if not isinstance(index, int):
            print "Argument must be integer."
            return
         
        # 結果の数を取得
        maxIndex = self._resultArray.PutSize() - 1

        if index > maxIndex:
            print "Argument must be between 0 and %d." % maxIndex
            return
                       
        return  self._resultArray.PutPointer(index)       
    
    ######################################### 
    def GetECArray(self): 
        """
        結果取得(ElementContainerArray)
        @param  無し
        @retval ElementContainerArray
        """ 
        # 結果があるか
        if self._resultArray == None:
            print "There is no result."
            return 
        
        return  self._resultArray      
             
    ######################################### 
    def _ConvertToDouble(self, num): 
        """
        領域の範囲チェック
        @param  num  領域(x0,y0, x1,y1)を格納したリスト
        @retval チェックの可否 True or False
        """                                                                     
        if isinstance(num, float): 
            return num
        elif isinstance(num, int) or isinstance(num, str): 
            return float(num)
        else:
            raise                          

    ######################################### 
    def _CheckRegion(self, region): 
        """
        領域の範囲チェック
        @param  region  領域(x0,y0, x1,y1)を格納したリスト
        @retval チェックの可否 True or False
        """ 
        # 実数に変換可能か
        try:
            region[0] = self._ConvertToDouble(region[0])   
            region[1] = self._ConvertToDouble(region[1])
            region[2] = self._ConvertToDouble(region[2])
            region[3] = self._ConvertToDouble(region[3])
        except:
            print "Argument must be numeric"
            return
        
        if region[0] > region[2]:
            print "x1 must be bigger or equal to x0."
            return False
        
        if region[1] > region[3]:
            print "y1 must be bigger or equal to x0."
            return False
 
        return True          
                    
#####################################################################
if __name__ == '__main__':
    """
    以下はテスト用のスクリプト

    """

    m2c = M2Clip()
    m2c.SetMask("c:\\tmp\\mask.txt")

