#include "UtsusemiTrignetDictionary.hh"
//////////////////////////////////////////////////////////
UtsusemiTrignetDictionary::
UtsusemiTrignetDictionary(){
    Initialize();
}
//////////////////////////////////////////////////////////
UtsusemiTrignetDictionary::
~UtsusemiTrignetDictionary(){

}
//////////////////////////////////////////////////////////
void UtsusemiTrignetDictionary::
Initialize(){
    TrigDic.clear();
    TypeDic.clear();

    TrigDic.resize(33,"");
    TypeDic.resize(8,"");

    TrigDic[0]="DIO1R";
    TrigDic[1]="DIO2R";
    TrigDic[2]="DIO3R";
    TrigDic[3]="DIO4R";
    TrigDic[4]="DIO5R";
    TrigDic[5]="DIO6R";
    TrigDic[6]="DIO7R";
    TrigDic[7]="DIO8R";
    TrigDic[14]="T0R";
    TrigDic[15]="TI";
    TrigDic[16]="DIO1F";
    TrigDic[17]="DIO2F";
    TrigDic[18]="DIO3F";
    TrigDic[19]="DIO4F";
    TrigDic[20]="DIO5F";
    TrigDic[21]="DIO6F";
    TrigDic[22]="DIO7F";
    TrigDic[23]="DIO8F";
    TrigDic[31]="SW";
    TrigDic[32]="ANY";

    TypeDic[1]="DIO";
    TypeDic[2]="LADC1";
    TypeDic[3]="LADC2";
    TypeDic[4]="HADC";

    MessageTag = "UtsusemiTrignetDictionary:: ";
}
//////////////////////////////////////////////////////////
std::string UtsusemiTrignetDictionary::
PutTrigString( UInt4 sid1 ){
    if (sid1>TrigDic.size()){
        UtsusemiError(MessageTag+"PutTrigString >> Too high value of sid1");
        return "";
    }
    return TrigDic[sid1];
}
//////////////////////////////////////////////////////////
std::string UtsusemiTrignetDictionary::
PutTypeString( UInt4 sid2 ){
    if (sid2>TypeDic.size()){
        UtsusemiError(MessageTag+"PutTypeString >> Too high value of sid2");
        return "";
    }
    return TypeDic[sid2];
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetDictionary::
PutTrigIndex( std::string trig ){
    Int4 ret = -1;
    if (trig!=""){
        for (UInt4 i=0;i<TrigDic.size();i++){
            if (TrigDic[i]==trig){
                ret = i;
                break;
            }
        }
    }

    if (ret==-1){
        UtsusemiWarning(MessageTag+"PutTrigIndex >> Not much Trigger string "+trig);
    }
    return ret;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetDictionary::
PutTypeIndex( std::string type ){
    Int4 ret = -1;
    if (type!=""){
        for (UInt4 i=0;i<TypeDic.size();i++){
            if (TypeDic[i]==type){
                ret = i;
                break;
            }
        }
    }
    if (ret==-1){
        UtsusemiWarning(MessageTag+"PutTypeIndex >> Not much Type string "+type);
    }
    return ret;
}



////////////////////////////////////////////////////////////////
//  UtsusemiTrignetCondition
//////////////////////////////////////////////////////////
UtsusemiTrignetCondition::
UtsusemiTrignetCondition(){

    Index = -1;
    Trigger = -1;
    Type = -1;
    Title = "untitled";
    Attr = "";
    IncrementalVal=0.0;
    IsAnd = true;
    Contents.clear();
}
//////////////////////////////////////////////////////////
UtsusemiTrignetCondition::
UtsusemiTrignetCondition( const UtsusemiTrignetCondition& obj ){
    Index = obj.Index;
    Trigger = obj.Trigger;
    Type = obj.Type;
    Title = obj.Title;
    Attr = obj.Attr;
    IncrementalVal = obj.IncrementalVal;
    IsAnd = obj.IsAnd;
    for (UInt4 i=0;i<obj.Contents.size();i++) Contents.push_back( obj.Contents[i] );
    //std::cout << "UtsusemiTrignetCondition:: Copy Constructor " << std::endl;
}
//////////////////////////////////////////////////////////
UtsusemiTrignetCondition::
~UtsusemiTrignetCondition(){
}
//////////////////////////////////////////////////////////
void UtsusemiTrignetCondition::
Dump(){
    std::cout << "---[ UtsusemiTrignetCondition Dump ]---" << std::endl;
    std::cout << " Index " << Index << std::endl;
    std::cout << " Trigger " << Trigger << std::endl;
    std::cout << " Type " << Type << std::endl;
    std::cout << " Title " << Title << std::endl;
    std::cout << " Attr " << Attr << std::endl;
    std::cout << " IncrementalVal " << IncrementalVal << std::endl;
    std::cout << " Contents :";
    if (Contents.empty()) {
        std::cout << " empty" << std::endl;
    }else{

        for (UInt4 i=0;i<Contents.size();i++)
            std::cout << Contents[i] << ",";
        std::cout << std::endl;
    }
    std::cout << "----------------------------------------" << std::endl;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondition::
SetIndex(Int4 ind){
    Index = ind;
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondition::
SetTrig(std::string trig){
    UtsusemiTrignetDictionary _UTD;
    Trigger = _UTD.PutTrigIndex( trig );
    if (Trigger<0){
        return -1;
    }else{
        return 0;
    }
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondition::
SetType(std::string type){
    UtsusemiTrignetDictionary _UTD;
    Type = _UTD.PutTypeIndex( type );
    if (Type<0){
        return -1;
    }else{
        return 0;
    }
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondition::
SetTitle(std::string title){
    if (title!=""){
        Title = title;
    }
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondition::
SetAttr(std::string attr){
    if (attr!=""){
        Attr = attr;
    }
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondition::
SetCont(std::vector<UInt4> cont){
    if ((Trigger<0)||(Type<0)){
        return -1;
    }
    Contents.clear();
    if (cont.empty()){
    }else{
        for (UInt4 i=0;i<cont.size();i++) Contents.push_back( cont[i] );
    }
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondition::
SetAnd(bool is_and){
    IsAnd = is_and;
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondition::
Check(UInt4 index, UInt4 trig, UInt4 type, const std::vector<UInt4>* cond, std::string title){
    Int4 ret = 0;
    if ((Index>=0)&&(Index!=(Int4)index)){
        return ret;
    }
    if (Trigger!=32){
        if ((Trigger>=0)&&(Trigger!=(Int4)trig)){
            return ret;
        }
    }
    if ((Type>=0)&&(Type!=(Int4)type)){
        return ret;
    }

    if (Contents.empty()){
        ret = 1;
    }else{
        if (type==1) {
            ret = 1;
            for (UInt4 i=0;i<8;i++){
                if (Contents[i]!=2){
                    if (cond->at(i)!=Contents[i]) ret = -1;
                }
            }

        }else if ((type==2)||(type==3)){
            ret = -1;
            for (UInt4 i=0;i<Contents.size();i+=2){
                if ( (cond->at(0) >= Contents[i] )&&( (Contents[i+1]==0)||(cond->at(0)<=Contents[i+1]) ) ){
                    ret = 1;
                    break;
                }
            }
        }else if (type==4){
            ret = 1;
            if ( (cond->at(0) < Contents[0]) || (cond->at(0) > Contents[1]) ) ret = -1;
            if ( (cond->at(1) < Contents[2]) || (cond->at(1) > Contents[3]) ) ret = -1;
        }
    }

    if ((title!="")&&(title!=Title)) ret=0;
    return ret;
}


////////////////////////////////////////////////////////////////
//  UtsusemiTrignetCondGroup
//////////////////////////////////////////////////////////
UtsusemiTrignetCondGroup::
UtsusemiTrignetCondGroup(){
    _TriggerCondArray.clear();
    _TimeRangeCondArray.clear();
    _TofRangeCondArray.clear();
    _TriggerCondArrayIsAnd = false;
    _TriggerCondArrayAndList.clear();
}
//////////////////////////////////////////////////////////
UtsusemiTrignetCondGroup::
UtsusemiTrignetCondGroup( const UtsusemiTrignetCondGroup& obj ){
    _TriggerCondArray.clear();
    _TriggerCondArray.resize(obj._TriggerCondArray.size());
    for (UInt4 i=0;i<obj._TriggerCondArray.size();i++){
        _TriggerCondArray[i] = obj._TriggerCondArray[i];
    }
    _TriggerCondArrayIsAnd = obj._TriggerCondArrayIsAnd;
    _TriggerCondArrayAndList.clear();
    _TriggerCondArrayAndList.resize(obj._TriggerCondArrayAndList.size());
    for (UInt4 i=0;i<obj._TriggerCondArrayAndList.size();i++)
        _TriggerCondArrayAndList[i]=obj._TriggerCondArrayAndList[i];

    _TimeRangeCondArray.clear();
    _TimeRangeCondArray.resize(obj._TimeRangeCondArray.size());
    for (UInt4 i=0;i<obj._TimeRangeCondArray.size();i++){
        for (UInt4 j=0;j<obj._TimeRangeCondArray[i].size();j++){
            _TimeRangeCondArray[i].push_back( obj._TimeRangeCondArray[i][j] );
        }
    }

    _TofRangeCondArray.clear();
    _TofRangeCondArray.resize(obj._TofRangeCondArray.size());
    for (UInt4 i=0;i<obj._TofRangeCondArray.size();i++){
        _TofRangeCondArray[i].first = obj._TofRangeCondArray[i].first;
        _TofRangeCondArray[i].second = obj._TofRangeCondArray[i].second;
    }
    //std::cout << "UtsusemiTrignetCondGroup:: Copy Constructor " << std::endl;
}
//////////////////////////////////////////////////////////
UtsusemiTrignetCondGroup::
~UtsusemiTrignetCondGroup(){
}
//////////////////////////////////////////////////////////
void UtsusemiTrignetCondGroup::
AppendTofRangeCond( std::pair<Double,Double> tofrange ){
    _TofRangeCondArray.push_back( tofrange );
}
//////////////////////////////////////////////////////////
void UtsusemiTrignetCondGroup::
AppendTimeRangeCond( std::string type, std::vector<Double> timerange ){
    std::vector<Double> tmp;
    if (type=="PASS"){
        if (timerange.size()>=2){
            tmp.push_back( 0.0 ); // type
            for (UInt4 i=0;i<timerange.size();i+=2){
                tmp.push_back( timerange[i] );   // [second]
                tmp.push_back( timerange[i+1] ); // [second]
            }
        }
    }else if (type=="MLF"){
        if (timerange.size()>=2){
            tmp.push_back( 1.0 ); // type
            for (UInt4 i=0;i<timerange.size();i+=2){
                // unit must be MLF clock [second] started from 2008.01.01
                tmp.push_back( timerange[i] );
                tmp.push_back( timerange[i+1] );
            }
        }
    }else if (type=="DATE"){
        if (timerange.size()>=14){
            tmp.push_back( 2.0 ); // type
            std::vector<Double> vec1(7,0.0), vec2(7,0.0);
            for (UInt4 j=0;j<7;j++){
                vec1[j] = timerange[j];
                vec2[j] = timerange[j+7];
            }
            T0TreatToolsBase _T0T;
            tmp.push_back( _T0T.convertDateTimeToInstClock( vec1 ) ); // [second]
            tmp.push_back( _T0T.convertDateTimeToInstClock( vec2 ) ); // [second]
        }
    }else{
        std::cout << "UtsusemiTrignetCondGroup::AppendTimeRangeCond >>> wrong type="<< type << std::endl;
    }

    if (tmp.empty()){
        UtsusemiError("UtsusemiTrignetCondGroup::AppendTimeRangeCond > wrong parameters ,type="+type);
        for (UInt4 i=0; i<timerange.size(); i++)
            std::cout << i << ":" << timerange[i] << std::endl;
    }
    /*
    Double v_type = 0.0;
    if (type=="PASS") v_type=0.0;
    if (type=="MLF") v_type=1.0;
    if (type=="DATE") v_type=2.0;

    std::vector<Double> tmp;
    tmp.push_back( v_type );
    for (UInt4 i=0;i<timerange.size();i++) {
        tmp.push_back( timerange[i] );
    }
    */
    //for (UInt4 i=0;i<tmp.size();i++) std::cout << "UtsusemiTrignetCondGroup::AppendTimeRangeCond tmp[i]="<<tmp[i]<<std::endl;
    _TimeRangeCondArray.push_back( tmp );
}
//////////////////////////////////////////////////////////
void UtsusemiTrignetCondGroup::
AppendTrigCond( UtsusemiTrignetCondition trigcond){
    _TriggerCondArray.push_back(trigcond);
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondGroup::
TrigFilter(UInt4 index, UInt4 trig, UInt4 type, const std::vector<UInt4>* cond){
    if (_TriggerCondArray.empty()) return 0;

    //for (UInt4 i=0;i<_TriggerCondArray.size();i++)
    //if (_TriggerCondArray[i].Check( index, trig, type, cond )) return true;
    //return false;

    std::vector<Int4> flag( _TriggerCondArray.size(),0);
    for (UInt4 i=0;i<(_TriggerCondArray.size());i++)
        flag[i]=_TriggerCondArray[i].Check( index, trig, type, cond );

    if (_TriggerCondArrayIsAnd){
        // AND condition
        // If flags have a false, return false
        for (UInt4 i=0; i<flag.size(); i++){
            if (flag[i]==-1) return -1;
        }
        // At this moment, flags includ only 0 or 1.
        for (UInt4 i=0; i<flag.size(); i++){
            if (flag[i]==1) return 1;
        }
    }else{
        // OR condition
        // If flags have a true, return true
        for (UInt4 i=0; i<flag.size(); i++){
            if (flag[i]==1) return 1;
        }
        // Here, flags include 0 or -1 only.
        for (UInt4 i=0; i<flag.size(); i++){
            if (flag[i]==-1) return -1;
        }
    }
    // All flags are 0.
    return 0;

}

//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondGroup::
TimeFilter( Double time_in, Double first_clock ){
    if (_TimeRangeCondArray.empty()) return 0;
    //T0TreatToolsBase _T0T;
    Int4 ret = -1;
    for (UInt4 i=0;i<_TimeRangeCondArray.size();i++){
        std::vector<Double> t = _TimeRangeCondArray[i];
        if (t.empty()) continue;
        if (t[0]==0.0){
            for (UInt4 j=1;j<t.size();j+=2){
                Double s_clock = first_clock + t[j]; // convert unit from second to clock
                Double e_clock = first_clock + t[j+1]; // convert unit from second to clock
                if (( s_clock<=time_in )&&( e_clock>=time_in )){
                    ret = 1;
                    break;
                }
            }
        }else{
            for (UInt4 j=1;j<t.size();j+=2){
                if (( t[j]<=time_in )&&( t[j+1]>=time_in )){
                    ret = 1;
                    break;
                }
            }
        }
        if (ret!=-1) break;
        /*
        }else if (t[0]==1.0){
            for (UInt4 j=1;j<t.size();j+=2){
                if (( t[j]<=time_in )&&( t[j+1]>=time_in )){
                    ret = 1;
                    break;
                }
            }
        }else if (t[0]==2.0){
            std::vector<Double> vec1(7,0.0),vec2(7,0.0);
            for (UInt4 j=0;j<7;j++) {
                vec1[j]= t[j+1];
                vec2[j]= t[j+1+7];
            }
            Double v1 = _T0T.convertDateTimeToInstClock( vec1 );
            Double v2 = _T0T.convertDateTimeToInstClock( vec2 );
            if ((v1<time_in)&&(v2>=time_in)){
                ret = 1;
                break;
            }
        }else{
        }
        */
    }
    return ret;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCondGroup::
TofFilter( Double tof_in ){
    if (_TofRangeCondArray.empty()) return 0;

    Int4 ret = -1;
    for (UInt4 i=0;i<_TofRangeCondArray.size();i++){
        std::pair<Double,Double> t = _TofRangeCondArray[i];
        if ((t.first<=tof_in)&&(t.second>=tof_in)) ret = 1;
    }
    return ret;
}
//////////////////////////////////////////////////////////
void UtsusemiTrignetCondGroup::
MakeCondArrayAndList(){
    if (_TriggerCondArrayAndList.empty()) return;
    for (std::vector<UtsusemiTrignetCondition>::iterator it=_TriggerCondArray.begin(); it!=_TriggerCondArray.end();++it){
        std::vector<UInt4>::iterator p = find( _TriggerCondArrayAndList.begin(), _TriggerCondArrayAndList.end(), (*it).Index );
        if (p== _TriggerCondArrayAndList.end())
            _TriggerCondArrayAndList.push_back( (*it).Index );
    }
    sort( _TriggerCondArrayAndList.begin(), _TriggerCondArrayAndList.end() );
}
//////////////////////////////////////////////////////////
void UtsusemiTrignetCondGroup::
Dump(){
    std::cout << "------[ UtsusemiTrignetCondGroup::Dump() ]---" << std::endl;
    std::cout << "---------------------------------------------" << std::endl;
    std::cout << "[TriggerCondArray Infor]" << std::endl;
    std::cout << "   TriggerCondArrayIsAnd = ";
    if (_TriggerCondArrayIsAnd) std::cout << "True" << std::endl;
    else std::cout << "False" << std::endl;
    std::cout << "   TriggerCondArrayAndList " << std::endl;
    for (UInt4 i=0;i<_TriggerCondArrayAndList.size();i++){
        std::cout << "  i= " << i << " : ";
        if (_TriggerCondArrayAndList[i]) std::cout << "True" << std::endl;
        else std::cout << "False" << std::endl;
    }
    for (UInt4 i=0;i<_TriggerCondArray.size();i++) _TriggerCondArray[i].Dump();
    std::cout << "--------------" << std::endl;
    for (UInt4 i=0;i<_TimeRangeCondArray.size();i++){
        std::cout << "[TimeRangeCondArray i="<< i <<"]"<< std::endl;
        std::vector<Double> t = _TimeRangeCondArray[i];
        std::cout << "Cont=";
        for (UInt4 j=0;j<t.size();j++) std::cout << t[j] << ",";
        std::cout << std::endl;
    }
    std::cout << "--------------" << std::endl;
    for (UInt4 i=0;i<_TofRangeCondArray.size();i++){
        std::cout << "[TofRangeCondArray i="<< i <<"]"<< std::endl;
        std::pair<Double,Double> t = _TofRangeCondArray[i];
        std::cout << "Cont=" << t.first << "," << t.second << std::endl;
    }
}



////////////////////////////////////////////////////////////////
//  UtsusemiTrignetCounter
//////////////////////////////////////////////////////////
UtsusemiTrignetCounter::
UtsusemiTrignetCounter(){
    Type=-1;
    ABphases.first = -1;
    ABphases.second = -1;
    Triggers.clear();
    ConvVal = 0.0;
    OrgVal = 0.0;
    ConditionType = -1;
    ConditionList.clear();
    Counts = 0.0;
    Unit = "Counts";
    StartClock = 0.0;
    hasFirstTrigerAsTimeStart = false;
    CyclicRegion.first = 0.0;
    CyclicRegion.second = 0.0;
    hasCyclicRegion = false;
    priorityOnVirtualKicker = "signal";
    stools = new StringTools();
    _preTrig = 999;
    _preCase = 0;
    _trigAR = 999;
    _trigAD = 999;
    _trigBR = 999;
    _trigBD = 999;
    ConditionRange.first = +1e100;
    ConditionRange.second = -1e100;
    ignoreKickerInConditionRange = true;
}
//////////////////////////////////////////////////////////
UtsusemiTrignetCounter::
UtsusemiTrignetCounter(const UtsusemiTrignetCounter& obj){
    Type = obj.Type;
    ABphases.first = obj.ABphases.first;
    ABphases.second = obj.ABphases.second;;
    Triggers.clear();
    for (UInt4 i=0;i<obj.Triggers.size();i++) Triggers.push_back( obj.Triggers[i] );
    ConvVal = obj.ConvVal;
    OrgVal = obj.OrgVal;
    ConditionType = obj.ConditionType;
    ConditionList.clear();
    if (obj.ConditionList.empty()){
    }else{
        ConditionList.resize( obj.ConditionList.size(), NULL );
        for (UInt4 i=0;i<obj.ConditionList.size();i++) {
            if (obj.ConditionList[i]!=NULL){
                ConditionList[i] = new std::vector<Double>;
                for (UInt4 j=0;j<obj.ConditionList[i]->size();j++){
                    ConditionList[i]->push_back( obj.ConditionList[i]->at(j) );
                }
            }
        }
    }
    Counts = obj.Counts;
    CyclicRegion.first = obj.CyclicRegion.first;
    CyclicRegion.second = obj.CyclicRegion.second;
    hasCyclicRegion = obj.hasCyclicRegion;
    priorityOnVirtualKicker = obj.priorityOnVirtualKicker;
    _preTrig = obj._preTrig;
    _preCase = obj._preCase;
    _trigAR = obj._trigAR;
    _trigAD = obj._trigAD;
    _trigBR = obj._trigBR;
    _trigBD = obj._trigBD;
    ConditionRange.first = obj.ConditionRange.first;
    ConditionRange.second = obj.ConditionRange.second;

}
//////////////////////////////////////////////////////////
UtsusemiTrignetCounter::
~UtsusemiTrignetCounter(){
    delete stools;
    for (UInt4 i=0;i<ConditionList.size();i++){
        if (ConditionList[i]!=NULL) delete ConditionList[i];
    }
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCounter::
SetType( std::string type ){
    if (type=="ABP"){
        Type = 0;
    }else if (type=="NORMAL"){
        Type = 1;
    }else if (type=="ABC"){ // value converted from Line Drive A-Bphase on DAQ LineDriveConvTrignetMlf module
        Type = 2;
    }else if (type=="KICKCOUNT"){ // use one signal is virtual Kicker and the other is counter signal
        Type = 3;
    }else{
        Type = -1;
    }
    return Type;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCounter::
AddTriggers( UtsusemiTrignetCondition trig ){
    if (trig.Attr!="")
        trig.IncrementalVal = stools->StringToDouble( trig.Attr );
    if (trig.IncrementalVal==0.0)
        trig.IncrementalVal=1.0;
    Triggers.push_back( trig );
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCounter::
AddAsABphase( UtsusemiTrignetCondition trig ){
    //std::cout << "UtsusemiTrignetCounter::AddAsABphase start" << std::endl;
    //trig.Dump();

    Int4 trig_id = trig.Trigger;
    if (trig_id<0) return -1;
    if ((trig_id>15)&&(trig_id<24)) trig_id -= 16;

    if (trig.Attr=="A") ABphases.first = trig_id;
    if (trig.Attr=="B") ABphases.second = trig_id;

    if ((ABphases.first<0)||(ABphases.second<0)){
    }else{

        UtsusemiTrignetCondition AR;
        UtsusemiTrignetCondition AD;
        UtsusemiTrignetCondition BR;
        UtsusemiTrignetCondition BD;
        AR.Trigger = ABphases.first;
        AD.Trigger = ABphases.first + 16;
        BR.Trigger = ABphases.second;
        BD.Trigger = ABphases.second + 16;

        _trigAR = AR.Trigger;
        _trigAD = AD.Trigger;
        _trigBR = BR.Trigger;
        _trigBD = BD.Trigger;

        AR.Type = AD.Type = BR.Type = BD.Type = 1;

        AR.Attr =  "AR";
        AD.Attr =  "AD";
        BR.Attr =  "BR";
        BD.Attr =  "BD";

        std::vector<UInt4> cont(8,2);
        AR.SetCont( cont );
        AD.SetCont( cont );
        BR.SetCont( cont );
        BD.SetCont( cont );

        AR.Contents[ AR.Trigger ]=1;
        AR.Contents[ BR.Trigger ]=0;
        AD.Contents[ AR.Trigger ]=0;
        AD.Contents[ BR.Trigger ]=1;
        BR.Contents[ AR.Trigger ]=1;
        BR.Contents[ BR.Trigger ]=1;
        BD.Contents[ AR.Trigger ]=0;
        BD.Contents[ BR.Trigger ]=0;

        Triggers.clear();
        Triggers.push_back( AR );
        Triggers.push_back( AD );
        Triggers.push_back( BR );
        Triggers.push_back( BD );

    }

    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCounter::
SetConvVal( std::string convval ){
    ConvVal = stools->StringToDouble( convval );
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCounter::
SetOrgVal( std::string orgval,std::string unit_in ){
    OrgVal = stools->StringToDouble( orgval );
    Unit = unit_in;
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCounter::
SetVirtualKickerPriority( std::string val){
    if ((val!="case")&&(val!="signal")){
        UtsusemiWarning("UtsusemiTrignetCounter::SetVirtualKickerPriority::  val is invalid.("+val+")");
        return -1;
    }
    priorityOnVirtualKicker = val;
    return 0;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCounter::
SetConditionType( std::string val ){
    ConditionType = stools->StringToInt4( val );
    return ConditionType;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCounter::
SetConditionList( UInt4 caseId, std::string conts ){
    if (caseId>=ConditionList.size()){
        ConditionList.resize( (caseId+1), NULL );
    }
    if (ConditionList[caseId]!=NULL) delete ConditionList[caseId];
    ConditionList[caseId] = new std::vector<Double>(3,0.0);
    std::vector<std::string> tmp = stools->SplitString( conts, "," );
    if (ConditionType==1){
        ConditionList[caseId]->at(0) = stools->StringToDouble( tmp[0] );
        ConditionList[caseId]->at(1) = stools->StringToDouble( tmp[1] );
        if (ConditionRange.first > stools->StringToDouble( tmp[0] ))
            ConditionRange.first = stools->StringToDouble( tmp[0] );
        if (ConditionRange.second < stools->StringToDouble( tmp[1] ))
            ConditionRange.second = stools->StringToDouble( tmp[1] );
    }else if (ConditionType==2){
        ConditionList[caseId]->at(0) = stools->StringToDouble( tmp[0] );
        ConditionList[caseId]->at(1) = stools->StringToDouble( tmp[1] );
        ConditionList[caseId]->at(2) = stools->StringToDouble( tmp[2] );
        if (ConditionRange.first > stools->StringToDouble( tmp[0] ))
            ConditionRange.first = stools->StringToDouble( tmp[0] );
        if (ConditionRange.second < stools->StringToDouble( tmp[1] ))
            ConditionRange.second = stools->StringToDouble( tmp[1] );
    }else{
        return -1;
    }

    return 0;

}
//////////////////////////////////////////////////////////
Int4 UtsusemiTrignetCounter::
SetCyclicRegion( std::string begin, std::string end ){
    CyclicRegion.first = stools->StringToDouble(begin);
    CyclicRegion.second = stools->StringToDouble(end);
    if (CyclicRegion.first>CyclicRegion.second){
        Double tmp = CyclicRegion.first;
        CyclicRegion.second = CyclicRegion.first;
        CyclicRegion.first = tmp;
    }
    if (CyclicRegion.first==CyclicRegion.second){
        hasCyclicRegion = false;
        return -1;
    }
    hasCyclicRegion = true;
    return 0;
}
//////////////////////////////////////////////////////////
UInt4 UtsusemiTrignetCounter::
SetClock( Double clock ){
    //UInt4 retCase=0;
    UInt4 retCase=_preCase;
    if ((Type==1)&&(Unit=="Clock")&&(hasFirstTrigerAsTimeStart)){
        retCase = UTSUSEMIMASKVALUEUINT4;
        Double val = clock - StartClock;
        if (hasCyclicRegion){
            while( val<CyclicRegion.first )
                val += ( CyclicRegion.second - CyclicRegion.first );
            while( val>CyclicRegion.second )
                val -= ( CyclicRegion.second - CyclicRegion.first );
        }
        //std::cout << "val=" << val << std::endl;
        if (ConditionType==1){
            for (UInt4 j=0;j<ConditionList.size();j++){
                double min_cond = UTSUSEMIMASKVALUE64;
                double max_cond = 1.0-UTSUSEMIMASKVALUE64;
                std::vector<Double>* tmp = ConditionList[j];
                if (tmp!=NULL){
                    if (tmp->at(0)<min_cond) min_cond = tmp->at(0);
                    if (tmp->at(1)>max_cond) max_cond = tmp->at(1);
                    if (((tmp->at(0))<val)&&(val<=(tmp->at(1)))) retCase = j;
                }
                //if (retCase==UTSUSEMIMASKVALUEUINT4) retCase=0;
                if (retCase==UTSUSEMIMASKVALUEUINT4){
                    if ((min_cond<val)&&(val<=max_cond)){
                        retCase = _preCase;
                    }else{
                        retCase=0;
                    }
                }
                //if (retCase==_preCase) retCase=0;
            }
        }else if (ConditionType==2){
            for (UInt4 j=0;j<ConditionList.size();j++){
                std::vector<Double>* tmp = ConditionList[j];
                if (tmp!=NULL){
                    if ((val>=(tmp->at(0)))&&(val<(tmp->at(1))))
                        retCase = (UInt4)((val-(tmp->at(0)))/(tmp->at(2)))+1;
                    else retCase = 0;
                }
            }
        }
        //std::cout << "val,case=" << val <<","<< retCase << std::endl;
        //if (retCase==0) std::cout << "val = " << val << std::endl;
        if (retCase!=UTSUSEMIMASKVALUEUINT4)
            _preCase = retCase;
    }
    return retCase;
}
//////////////////////////////////////////////////////////
UInt4 UtsusemiTrignetCounter::
CountEvent( UInt4 index, UInt4 trig, UInt4 type, const std::vector<UInt4>* cond, const Double clock){
    UInt4 retCase=UTSUSEMIMASKVALUEUINT4;
    if (Type==0){  //AB
        bool isCW = false;
        /*
        std::cout << "========================  ";
        std::cout << "index="<<index<<",trig="<<trig<<",type="<<type << ", cond=";
        for (UInt4 j=0;j<cond->size();j++) std::cout << cond->at(j) << ",";
        */
        /*
          Triger's order
          CW  : AR->BR->AD->BD->AR->...
          CCW : AR->BD->AD->BR->AR->...
         */
        if ((_preTrig==_trigAR)&&((trig!=_trigBR)&&(trig!=_trigBD))) return _preCase;
        if ((_preTrig==_trigBR)&&((trig!=_trigAD)&&(trig!=_trigAR))) return _preCase;
        if ((_preTrig==_trigAD)&&((trig!=_trigBD)&&(trig!=_trigBR))) return _preCase;
        if ((_preTrig==_trigBD)&&((trig!=_trigAR)&&(trig!=_trigAD))) return _preCase;

        for (UInt4 i=0;i<Triggers.size();i++){
            //Triggers[i].Dump();
            //std::cout << std::endl;
            if (Triggers[i].Check( index, trig, type, cond )==1){
                //std::cout << "HIT!!!!!" << std::endl;
                isCW = true;
                break;
            }
        }
        if (isCW){
            Counts += 1.0;
        }else{
            Counts -= 1.0;
        }
        _preTrig = trig;
        //std::cout <<"CoutEvent Count="<< Counts << ":";
    }
    // If Counter Trig is used as virtual kicker
    if ((Type==1)&&(Unit=="Clock")){
        if (priorityOnVirtualKicker=="case"){
            UInt4 case_clock=SetClock( clock );
            if (case_clock!=0) return case_clock;
        }
        for (UInt4 i=0;i<Triggers.size();i++){
            if (Triggers[i].Check( index, trig, type, cond )==1){
                StartClock = clock;
                _preCase = 0;
                hasFirstTrigerAsTimeStart=true;
            }
        }
        return retCase;
    }
    if (Type==1){   //Normal
        /*
        std::cout << "========================  ";
        std::cout << "index="<<index<<",trig="<<trig<<",type="<<type << ", cond=";
        for (UInt4 j=0;j<cond->size();j++) std::cout << cond->at(j) << ",";
        */
        for (UInt4 i=0;i<Triggers.size();i++){
            //Triggers[i].Dump();
            //std::cout << std::endl;
            if (Triggers[i].Check( index, trig, type, cond )==1){
                Counts += Triggers[i].IncrementalVal;
                /*
                if (Triggers[i].Attr=="-"){
                    Counts -= 1.0;
                }else{
                    Counts += 1.0;
                }
                */
            }else{
                //std::cout << "Check is Bad" << std::endl;
            }
        }
    }

    if (Type==2){  // Converted value from A-B pahse signals by DAQ LineDriveConvTrignetMlf module
        for (UInt4 i=0;i<Triggers.size();i++){
            if (Triggers[i].Check( index, trig, type, cond )==1){
                Counts = (Double)( (Int4)(cond->at(0)) -0x800000 );//8388608
                break;
            }
        }
    }

    if (Type==3){
        for (UInt4 i=0;i<Triggers.size();i++){
            if (Triggers[i].Check( index, trig, type, cond, "Kicker" )==1){
                if (hasFirstTrigerAsTimeStart){
                    if (ignoreKickerInConditionRange){
                        Double check_val = OrgVal + (ConvVal*Counts);
                        if (check_val > ConditionRange.second){
                            Counts = 0.0;
                        }else{
                            UtsusemiMessage("Skick Kicker in Condition range : val = " + stools->DoubleToString(check_val));
                            UtsusemiMessage("Skick Kicker in Condition range : ConditionRange Max = " + stools->DoubleToString(ConditionRange.second));
                        }
                    }else{
                        Counts = 0.0;
                    }
                }else{
                    Counts = 0.0;
                    hasFirstTrigerAsTimeStart=true;
                }
            }
            if (hasFirstTrigerAsTimeStart){
                if (Triggers[i].Check( index, trig, type, cond, "Counter" )==1){
                    Counts += 1.0;
                }
            }else{
                return retCase;
            }
        }
    }

    Double val = OrgVal + (ConvVal*Counts);
    if (hasCyclicRegion){
        while( val<CyclicRegion.first )
            val += ( CyclicRegion.second - CyclicRegion.first );
        while( val>CyclicRegion.second )
            val -= ( CyclicRegion.second - CyclicRegion.first );
    }
    //std::cout << "val=" << val << std::endl;
    if (ConditionType==1){
        for (UInt4 j=0;j<ConditionList.size();j++){
            std::vector<Double>* tmp = ConditionList[j];
            if (tmp!=NULL){
                if (((tmp->at(0))<val)&&(val<=(tmp->at(1)))){
                    retCase = j;
                    break;
                }
                else retCase = 0;
            }
        }
    }else if (ConditionType==2){
        for (UInt4 j=0;j<ConditionList.size();j++){
            std::vector<Double>* tmp = ConditionList[j];
            if (tmp!=NULL){
                if ((val<(tmp->at(0)))||(val>=(tmp->at(1)))){
                    retCase = 0;
                    break;
                }
                retCase = (UInt4)((val-(tmp->at(0)))/(tmp->at(2)))+1;
            }
        }
    }
    //std::cout << "val,case=" << val <<","<< retCase << std::endl;
    //if (retCase==0) std::cout << "val = " << val << std::endl;
    if (retCase!=UTSUSEMIMASKVALUEUINT4)
        _preCase = retCase;
    return retCase;
}
//////////////////////////////////////////////////////////
UInt4 UtsusemiTrignetCounter::
    CountEvent( std::vector<UInt4> index, std::vector<UInt4> trig, std::vector<UInt4> type, const std::vector< std::vector<UInt4>* > &cond){
    UInt4 ret = 0;
    for (UInt4 i=0;i<(index.size());i++)
        ret = CountEvent( index[i], trig[i], type[i], cond[i] );

    return ret;
}
//////////////////////////////////////////////////////////
void UtsusemiTrignetCounter::
Dump(){
    std::cout << "@@@  UtsusemiTrignetCounter dump  @@@" << std::endl;
    std::cout << "Type=" << Type << ": 0=Encoder A and B phases, 1=1DIO, 2=2DIOs.." << std::endl;
    std::cout << "ABphase=<" << ABphases.first << "," << ABphases.second << ">" << std::endl;
    //std::cout << "ABtags =<" << ABtags.first << "," << ABtags.second << ">" << std::endl;
    std::cout << "Triggers info" << std::endl;
    for (UInt4 i=0;i<Triggers.size();i++){
        std::cout << "==== [Index=" << i << "]=====";
        Triggers[i].Dump();
    }
    std::cout << "ConversionVal=" << ConvVal << std::endl;
    std::cout << "Origin valu [unit]=" << OrgVal << "[" << Unit << "]" << std::endl;
    std::cout << "ConditionType=" << ConditionType << std::endl;
    std::cout << "ConditionList: size="<<ConditionList.size()<< std::endl;
    std::cout << "               ";
    if (ConditionList.empty()){
        std::cout << "Empty" << std::endl;
    }else{
        for (UInt4 i=0;i<ConditionList.size();i++){
            if (ConditionList[i]!=NULL){
                std::vector<Double>* cond = ConditionList[i];
                for (UInt4 j=0;j<(cond->size());j++){
                    std::cout << cond->at(j) << ",";
                }
                std::cout << std::endl;
            }
        }
    }
}
