#include "DetectorInfoEditorReadout2d.hh"
//////////////////////////////////////////////////////////
DetectorInfoEditorReadout2d::
DetectorInfoEditorReadout2d()
{
    Initialize();
}
//////////////////////////////////////////////////////////
DetectorInfoEditorReadout2d::
DetectorInfoEditorReadout2d( std::string dfile, bool workAsReader){
    Initialize();
    if ( Read(dfile) ){
        if (workAsReader){
            if (SetInfoAsReader()) _Status=true;
            else _Status = false;
        }
    }else{
        UtsusemiError( _MessageTag+"constructor Base:Read fails" );
        _Status=false;
    }
}
//////////////////////////////////////////////////////////
DetectorInfoEditorReadout2d::
~DetectorInfoEditorReadout2d()
{
    Clear(0);
    ClearReader(0);
}

//////////////////////////////////////////////////////////
void DetectorInfoEditorReadout2d::
Initialize(){
    _MessageTag = "DetectorInfoEditorReadout2d::";
    detPositionInfoVect = NULL;
}
//////////////////////////////////////////////////////////
void DetectorInfoEditorReadout2d::
Clear( UInt4 index ){
    DetectorInfoEditorBase::Clear(index);
}
//////////////////////////////////////////////////////////
bool DetectorInfoEditorReadout2d::
Read( std::string arg ){
    if (DetectorInfoEditorBase::Read(arg)){
        // required only for NEUNET
        _Status = true;
    }
    return _Status;
}
//////////////////////////////////////////////////////////
bool DetectorInfoEditorReadout2d::
Write( std::string filepath ){
    if (_makeOutputXmlReadout2d()){
        _parser->Save( KEY_WRITE_XML, filepath );
    }else{
        UtsusemiError( _MessageTag+"Write : false to make output XML from given information. " );
        return false;
    }
    return true;
}
//////////////////////////////////////////////////////////
std::string DetectorInfoEditorReadout2d::
OutXml( bool withIndent ){
    if (_makeOutputXmlReadout2d()){
        // required only for NEUNTE
        return _parser->OutToString( KEY_WRITE_XML, "", withIndent );
    }else{
        UtsusemiError( _MessageTag+"OutXml : false to make output XML from given information. " );
        return "";
    }
}
//////////////////////////////////////////////////////////
bool DetectorInfoEditorReadout2d::
_makeOutputXmlReadout2d(){
    if (DetectorInfoEditorBase::_makeOutputXml()){
        // required only for Readout 2D
    }else{
        UtsusemiError( _MessageTag+"_makeOutputXmlReadout2d >> _makeOutputXml fails" );
        return false;
    }
    return true;
}
//////////////////////////////////////////////////////////
void DetectorInfoEditorReadout2d::
ClearReader( UInt4 index ){
    DetectorInfoEditorBase::ClearReader(index);
    if ((index==0)||(index==4)){
        if (detPositionInfoVect!=NULL){
            for (UInt4 i=0;i<(detPositionInfoVect->size()); i++)
                if (detPositionInfoVect->at(i)!=NULL) delete detPositionInfoVect->at(i);
            detPositionInfoVect->clear();
            detPositionInfoVect=NULL;
        }
    }
}
//////////////////////////////////////////////////////////
bool DetectorInfoEditorReadout2d::
SetInfoAsReader(){
    ClearReader(0);
    if (DetectorInfoEditorBase::SetInfoAsReader()){
        // required only for NEUNET
        if (PosiInfo==NULL) UtsusemiWarning( _MessageTag+"----- PosiInfo is NULL" );
        if (detPositionInfoVect==NULL)
            detPositionInfoVect = new std::vector< std::vector<Double>* >( PosiInfo->position_list.size(), NULL);
        for (UInt4 detid=0; detid<(PosiInfo->position_list.size()); detid++){
            if (PosiInfo->numAxis_list[detid]==2){  // use only 2D
                if (detPositionInfoVect->at(detid)==NULL)
                    detPositionInfoVect->at(detid) = new std::vector<Double>( PosiInfo->position_list[detid].size(), 0.0);
                for (UInt4 i=0; i<(PosiInfo->position_list[detid].size()); i++)
                    detPositionInfoVect->at(detid)->at(i) = PosiInfo->position_list[detid][i];
            }
        }
    }else{
        UtsusemiError( _MessageTag+"SetInfoAsReader : fails to do Base::SetInfoAsReader " );
        return false;
    }
    return true;
}
//////////////////////////////////////////////////////////
bool DetectorInfoEditorReadout2d::
CalcReadout2dPixelPosition(UInt4 det_id, UInt4 x_size, UInt4 y_size, std::vector< std::vector<Double>* >* posi_vec ){
    if (detPositionInfoVect==NULL){
        UtsusemiError( _MessageTag+"CalcReadout2dPixelPosition >> not SetInfoAsReader " );
        return false;
    }
    if (((det_id+1)>(detPositionInfoVect->size()))||((detPositionInfoVect->at(det_id))==NULL)){
        StringTools st;
        UtsusemiError( _MessageTag+"Invalid detId ("+st.UInt4ToString( det_id )+")" );
        return false;
    }
    if ((posi_vec->size())<(x_size*y_size)){
        for (UInt4 i=0; i<(posi_vec->size()); i++)
            if (posi_vec->at(i)!=NULL) delete posi_vec->at(i);

        posi_vec->resize( (x_size*y_size), NULL );
        for (UInt4 i=0; i<(x_size*y_size); i++)
            posi_vec->at(i) = new std::vector<Double> (3,0.0);
    }
    std::vector<Double> *v = detPositionInfoVect->at( det_id );

    Double lenU = sqrt( (v->at(3))*(v->at(3)) + (v->at(4))*(v->at(4)) + (v->at(5))*(v->at(5)) );
    Double lenV = sqrt( (v->at(6))*(v->at(6)) + (v->at(7))*(v->at(7)) + (v->at(8))*(v->at(8)) );
    Double unitUx = (v->at(3))/lenU;
    Double unitUy = (v->at(4))/lenU;
    Double unitUz = (v->at(5))/lenU;
    Double unitVx = (v->at(6))/lenU;
    Double unitVy = (v->at(7))/lenU;
    Double unitVz = (v->at(8))/lenU;
    Double lenUpix = lenU/(Double)x_size;
    Double lenVpix = lenV/(Double)y_size;

    std::vector<Double> P0(3,0.0);
    P0[0] = (v->at(0)) - (v->at(9))*unitUx - (v->at(10))*unitVx;
    P0[1] = (v->at(1)) - (v->at(9))*unitUy - (v->at(10))*unitVy;
    P0[2] = (v->at(2)) - (v->at(9))*unitUz - (v->at(10))*unitVz;


    for (UInt4 py=0; py<y_size; py++){
        for (UInt4 px=0; px<x_size; px++){
            //UInt4 i = px*py;
            UInt4 i = py*x_size + px;
            if (posi_vec->at(i)==NULL) posi_vec->at(i)= new std::vector<Double> (3,0.0);
            posi_vec->at(i)->at(0) = P0[0] + unitUx*((Double)px + 0.5)*lenUpix + unitVx*((Double)py + 0.5)*lenVpix;
            posi_vec->at(i)->at(1) = P0[1] + unitUy*((Double)px + 0.5)*lenUpix + unitVy*((Double)py + 0.5)*lenVpix;
            posi_vec->at(i)->at(2) = P0[2] + unitUz*((Double)px + 0.5)*lenUpix + unitVz*((Double)py + 0.5)*lenVpix;
        }
    }
    return true;

}

//////////////////////////////////////////////////////////
std::vector<Double> DetectorInfoEditorReadout2d::
CalcReadout2dPixelSolidAngle( UInt4 det_id, UInt4 x_size, UInt4 y_size, std::vector< std::vector<Double>* >* posi_vec ){
    if (detPositionInfoVect==NULL){
        UtsusemiError( _MessageTag+"CalcReadout2dSolidAngle >> not SetInfoAsReader " );
        std::vector<Double> ret_empty;
        return ret_empty;
    }
    if (((det_id+1)>(detPositionInfoVect->size()))||((detPositionInfoVect->at(det_id))==NULL)){
        StringTools st;
        UtsusemiError( _MessageTag+"Invalid detId ("+st.UInt4ToString( det_id )+")" );
        std::vector<Double> ret_empty;
        return ret_empty;
    }
    std::vector<Double> *v = detPositionInfoVect->at( det_id );
    std::vector<Double> Uvec(3,0.0);
    std::vector<Double> Vvec(3,0.0);
    Uvec[0] = v->at(3);
    Uvec[1] = v->at(4);
    Uvec[2] = v->at(5);
    Vvec[0] = v->at(6);
    Vvec[1] = v->at(7);
    Vvec[2] = v->at(8);
    std::vector<Double> Dv = CrossVectorNorm( Uvec, Vvec );
    Double dS = (v->at(11))*(v->at(12));
    Dv[0] = Dv[0]*dS;
    Dv[1] = Dv[1]*dS;
    Dv[2] = Dv[2]*dS;
    std::vector<Double> ret(posi_vec->size(),0.0);
    for (UInt4 i=0; i<(posi_vec->size()); i++){
        Double px = posi_vec->at(i)->at(0);
        Double py = posi_vec->at(i)->at(1);
        Double pz = posi_vec->at(i)->at(2);
        Double l = sqrt( px*px + py*py + pz*pz );
        ret[i] = fabs(-1.0*( px*Dv[0] + py*Dv[1] + pz*Dv[2] )/(l*l*l));
    }
    return ret;

}

//////////////////////////////////////////////////////////
std::vector<Double> DetectorInfoEditorReadout2d::
CrossVectorNorm( std::vector<Double> A, std::vector<Double> B ){
    UInt4 x=0;
    UInt4 y=1;
    UInt4 z=2;

    Double X = A[y]*B[z] - B[y]*A[z];
    Double Y = A[z]*B[x] - B[z]*A[x];
    Double Z = A[x]*B[y] - B[x]*A[y];

    Double l_vec = sqrt(X*X + Y*Y + Z*Z);

    std::vector<Double> ret;
    ret.clear();
    ret.push_back(X/l_vec);
    ret.push_back(Y/l_vec);
    ret.push_back(Z/l_vec);

    return ret;
}

