#include "AcquireNeutronSourceInformationControlBase.hh"
//////////////////////////////////////////////////////////
AcquireNeutronSourceInformationControlBase::
AcquireNeutronSourceInformationControlBase(){
    AccessCount = 0;
    gettimeofday( &StartingTime, NULL );
    LastTime.tv_sec = StartingTime.tv_sec - ACQUIRE_TIME;
    LastTime.tv_usec = StartingTime.tv_usec;

    //std::cout << std::endl;
    //std::cout << "InformationControlBase()" << std::endl;
    //std::cout << "StartingTime : " << StartingTime.tv_sec << std::endl;
}
//////////////////////////////////////////////////////////
AcquireNeutronSourceInformationControlBase::
AcquireNeutronSourceInformationControlBase( std::string host_name )
:AcquireNeutronSourceInformationBase( host_name ){
    AccessCount = 0;
    gettimeofday( &StartingTime, NULL );
    LastTime.tv_sec = StartingTime.tv_sec - ACQUIRE_TIME;
    LastTime.tv_usec = StartingTime.tv_usec;

    //std::cout << std::endl;
    //std::cout << "InformationControlBase(host_name)" << std::endl;
    //std::cout << "host_name : " << host_name << std::endl;
    //std::cout << "StartingTime : " << StartingTime.tv_sec << std::endl;
}
//////////////////////////////////////////////////////////
AcquireNeutronSourceInformationControlBase::
~AcquireNeutronSourceInformationControlBase(){
}
//////////////////////////////////////////////////////////
Bool AcquireNeutronSourceInformationControlBase::
AcquireControl( const std::string Key ){

    Bool result;
    struct timeval CurrentTime, ElapsedTime, LapTime;    /* micro sec */

    result = false;
    /* Image Information */
    if ( Key == BEAM_POWER            ||   /* Beam Power(image) */
         Key == CT_HISTORY            ||   /* Beam power history(image) */
         Key == MODERATOR_TEMPERATURE ||   /* Moderator temperature history(image) */
         Key == JPARC_STATUS          ||   /* Status of J-PARC(image) */
         Key == SHUTTER_STATUS        ||   /* Shutter opening-and-closing state(image) */
         Key == CT_3HOUR              ||   /* Current history 3 hour(image) */
         Key == CT_1DAY               ||   /* Current history 1 day(image) */
         Key.substr(0,5) == "/MLF/"   ) {  /* Other image file */
        if ( AccessCount > ACQUIRE_MAX ) {
            std::cout << "upper limit of the access number of times. " << std::endl;
            return result;
        }
    }

    /* Value or Text Information */
    else if (
         Key == H2_ENTRANCE                 ||   /* Temperature of moderator hydrogen (entrance) */
         Key == H2_COUPLED                  ||   /* Temperature of moderator hydrogen (coupled) */
         Key == H2_DECOUPLED                ||   /* Temperature of moderator hydrogen (decoupled) */
         Key == H2_POISON                   ||   /* Temperature of moderator hydrogen (poison) */
         Key == CT_MUON_TARGET              ||   /* The number of protons (muon target) */
         Key == CT_NEUTRON_TARGET           ||   /* The number of protons (neutron target) */
         Key == CT_NEUTRON_CORRECTED_TARGET ||   /* The number of protons corrected by muon target position  */
         Key == BEAM_STOP_START   ) {   /* Beam stop time */
    }

    else {
        std::cout << Key << " is an invalid keyword!" << std::endl;
        return result;
    }

    /* Now date and time*/
    gettimeofday( &CurrentTime, NULL );
    //std::cout << "CurrentTime : " << CurrentTime.tv_sec << std::endl;

    /* Lap time */
    timersub( &CurrentTime, &LastTime, &LapTime );
    //std::cout << "LapTime     : " << LapTime.tv_sec << std::endl;

    /* Elapsed time */
    timersub( &CurrentTime, &StartingTime, &ElapsedTime );
    //std::cout << "ElapsedTime : " << ElapsedTime.tv_sec << std::endl;

    /* Average access time interval */
    //UInt4 AccessCycle = (UInt4)(ElapsedTime.tv_sec / (time_t)(AccessCount+1));
    //Double AccessCycle = ElapsedTime.tv_sec + (Double)ElapsedTime.tv_usec*1e-6;
    //std::cout << "AccessCycle : " << AccessCycle << std::endl;
    //std::cout << "AccessCount : " << AccessCount << std::endl;

    Int4 wait_time = ACQUIRE_TIME - LapTime.tv_sec;
    if ( wait_time > 0 ){
        std::cout << ">>>>>>>>>>>>>>>>>>>> wait " << wait_time << " sec. <<<<<<<<<<<<<<<<<<<<" << std::endl;
        sleep( wait_time );  /* sleeped */
    }
    else {
    }
    result = true;
    AccessCount++;
    gettimeofday( &LastTime, NULL );
    //std::cout << "LastTime    : " << LastTime.tv_sec << std::endl;

    return result;
}
//////////////////////////////////////////////////////////////////////
UInt4 AcquireNeutronSourceInformationControlBase::
StringDateToUInt4( const std::string Date, UInt4& year, UInt4& month, UInt4& day, UInt4& hour ){
    std::string date_time;

    StringTools *st = new StringTools();

    /* year */
    std::string::size_type c = Date.find( '/' );
    if( !(c == std::string::npos) ){
        year = st->StringToUInt4( Date.substr(0,c) );
        date_time = Date.substr( c+1 );
    }
    else {
        return -1;
    }
    /* month */
    c = date_time.find( '/' );
    if( !(c == std::string::npos) ){
        month = st->StringToUInt4( date_time.substr(0,c) );
        date_time = date_time.substr( c+1 );
    }
    else {
        return -1;
    }
    /* day */
    c = date_time.find( ' ' );
    if( !(c == std::string::npos) ){
        day = st->StringToUInt4( date_time.substr(0,c) );
        date_time = date_time.substr( c+1 );
    }
    else {
        return -1;
    }
    /* hour */
    c = date_time.find( ':' );
    if( !(c == std::string::npos) ){
        hour = st->StringToUInt4( date_time.substr(0,c) );
    }
    else {
        c = date_time.length();
        hour = st->StringToUInt4( date_time.substr(0,c) );
    }

    return 0;
}
//////////////////////////////////////////////////////////
UInt4 AcquireNeutronSourceInformationControlBase::
StringTimeToStructTime( const std::string date_time, const std::string separator, struct tm *ltm ){

    StringTools *st = new StringTools();

    std::string::size_type pos_s, pos_e;

    /* year */
    pos_e = date_time.find( separator );
    if( !(pos_e == std::string::npos) ){
        ltm->tm_year = st->StringToUInt4( date_time.substr(0,pos_e) ) - 1900;
        pos_s = pos_e + 1;
    }
    else {
        return -1;
    }
    /* month */
    pos_e = date_time.find( separator, pos_s );
    if( !(pos_e == std::string::npos) ){
        ltm->tm_mon = st->StringToUInt4( date_time.substr(pos_s,pos_e-pos_s) ) - 1;
        pos_s = pos_e + 1;
    }
    else {
        return -1;
    }
    /* day */
    pos_e = date_time.find( ' ', pos_s );
    if( !(pos_e == std::string::npos) ){
        ltm->tm_mday = st->StringToUInt4( date_time.substr(pos_s,pos_e-pos_s) );
        pos_s = pos_e + 1;
    }
    else {
        return -1;
    }
    /* hour */
    pos_e = date_time.find( ':', pos_s );
    if( !(pos_e == std::string::npos) ){
        ltm->tm_hour = st->StringToUInt4( date_time.substr(pos_s,pos_e-pos_s) );
        pos_s = pos_e + 1;
    }
    else {
        return -1;
    }
    /* min */
    pos_e = date_time.find( ':', pos_s );
    if( !(pos_e == std::string::npos) ){
        ltm->tm_min = st->StringToUInt4( date_time.substr(pos_s,pos_e-pos_s) );
        pos_s = pos_e + 1;
    }
    else {
        return -1;
    }
    /* sec */
    pos_e = date_time.find( ' ', pos_s );
    if( !(pos_e == std::string::npos) ){
        ltm->tm_sec = st->StringToUInt4( date_time.substr(pos_s,pos_e-pos_s) );
    }
    else {
        ltm->tm_sec = st->StringToUInt4( date_time.substr(pos_s) );
    }

    return 0;
}
//////////////////////////////////////////////////////////
std::string AcquireNeutronSourceInformationControlBase::
StructTimeToStringTime( struct tm *ltm, const std::string separator ){
    std::ostringstream os;

    os << ltm->tm_year + 1900 << separator
       << std::setw(2) << std::setfill('0') << ltm->tm_mon + 1 << separator
       << std::setw(2) << ltm->tm_mday << " "
       << std::setw(2) << ltm->tm_hour << ":"
       << std::setw(2) << ltm->tm_min  << ":"
       << std::setw(2) << ltm->tm_sec        ;

    return os.str();
}
