#include "DetectorInfoEditorNeunet.hh"
//////////////////////////////////////////////////////////
DetectorInfoEditorNeunet::
DetectorInfoEditorNeunet()
{
    Initialize();
}
//////////////////////////////////////////////////////////
DetectorInfoEditorNeunet::
DetectorInfoEditorNeunet( std::string dfile, bool workAsReader){
    Initialize();
    if ( Read(dfile) ){
        if (workAsReader)
            SetInfoAsReader();
        _Status=true;
    }else{
        _Status=false;
    }
}
//////////////////////////////////////////////////////////
DetectorInfoEditorNeunet::
~DetectorInfoEditorNeunet()
{
    Clear(0);
    ClearReader(0);
}

//////////////////////////////////////////////////////////
void DetectorInfoEditorNeunet::
Initialize(){
    _MessageTag = "DetectorInfoEditorNeunet::";
    detPositionInfoVect = NULL;
}
//////////////////////////////////////////////////////////
void DetectorInfoEditorNeunet::
Clear( UInt4 index ){
    DetectorInfoEditorBase::Clear(index);
}
//////////////////////////////////////////////////////////
bool DetectorInfoEditorNeunet::
Read( std::string arg ){
    if (DetectorInfoEditorBase::Read(arg)){
        // required only for NEUNET
        _Status = true;
    }
    return _Status;
}
//////////////////////////////////////////////////////////
bool DetectorInfoEditorNeunet::
Write( std::string filepath ){
    if (_makeOutputXmlNeunet()){
        // required only for NEUNTE
        _parser->Save( KEY_WRITE_XML, filepath );
    }else{
        UtsusemiError( _MessageTag+"Write : false to make output XML from given information. " );
        return false;
    }
    return true;
}
//////////////////////////////////////////////////////////
std::string DetectorInfoEditorNeunet::
OutXml( bool withIndent ){
    if (_makeOutputXmlNeunet()){
        // 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 DetectorInfoEditorNeunet::
_makeOutputXmlNeunet(){
    if (DetectorInfoEditorBase::_makeOutputXml()){
        // required only for NEUNET
    }else{
        UtsusemiError( _MessageTag+"_makeOutputXmlNeunet >> _makeOutputXml fails" );
        return false;
    }
    return true;
}
//////////////////////////////////////////////////////////
void DetectorInfoEditorNeunet::
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();
            delete detPositionInfoVect;
            detPositionInfoVect=NULL;
        }
    }
}
//////////////////////////////////////////////////////////
bool DetectorInfoEditorNeunet::
SetInfoAsReader(){
    ClearReader(0);
    if (DetectorInfoEditorBase::SetInfoAsReader()){
        // required only for NEUNET
        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]==1){  // use only 1D PSD
                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{
        return false;
    }
    return true;
}
//////////////////////////////////////////////////////////
std::vector<double> DetectorInfoEditorNeunet::
CalcPsdPixelPosition( UInt4 det_id, UInt4 pixelNo, UInt4 numOfPixel ){
    if (detPositionInfoVect==NULL){
        UtsusemiError( _MessageTag+"CalcPsdPixelPosition >> not SetInfoAsReader " );
        std::vector<double> empty_vec;
        return empty_vec;
    }
    if (((det_id+1)>(detPositionInfoVect->size()))||((detPositionInfoVect->at(det_id))==NULL)){
        StringTools st;
        UtsusemiError( _MessageTag+"Invalid detId ("+st.UInt4ToString(det_id)+")" );
        std::vector<double> empty_vec;
        return empty_vec;
    }

    std::vector<Double> *v = detPositionInfoVect->at( det_id );
    Double L = sqrt( v->at(3)*v->at(3) + v->at(4)*v->at(4) + v->at(5)*v->at(5) );
    //std::cout << "v=" << v->at(0) <<","<<v->at(1)<<","<<v->at(2)<<","<<v->at(3)<<","<<v->at(4)<<","<<v->at(5)<<","<<v->at(6)<<std::endl;
    //std::cout << "pixelNo,numOfPixel="<< pixelNo <<","<<numOfPixel<<std::endl;
    std::vector<Double> pv;
    if (L!=0.0){
        pv.clear();
        pv.push_back(v->at(0) - (v->at(6)/L - ( (Double)pixelNo+0.5) /(Double)numOfPixel) * v->at(3));
        pv.push_back(v->at(1) - (v->at(6)/L - ( (Double)pixelNo+0.5) /(Double)numOfPixel) * v->at(4));
        pv.push_back(v->at(2) - (v->at(6)/L - ( (Double)pixelNo+0.5) /(Double)numOfPixel) * v->at(5));
        if (v->size()==8){
            Double dx = v->at(3)/(Double)numOfPixel;
            Double dy = v->at(4)/(Double)numOfPixel;
            Double dz = v->at(5)/(Double)numOfPixel;
            if (dx<(v->at(7))) dx=v->at(7);
            if (dy<(v->at(7))) dy=v->at(7);
            if (dz<(v->at(7))) dz=v->at(7);
            pv.push_back( dx );
            pv.push_back( dy );
            pv.push_back( dz );
        }
    }else{
        pv.clear();
        pv.resize(3,0.0);
    }

    return pv;

}

//////////////////////////////////////////////////////////
Double DetectorInfoEditorNeunet::
CalcPsdPixelSolidAngle( UInt4 det_id, UInt4 pixelNo, UInt4 numOfPixel ){
    if (detPositionInfoVect==NULL){
        UtsusemiError( _MessageTag+"CalcPsdSolidAngle >> not SetInfoAsReader " );
        return 0.0;
    }
    if (((det_id+1)>(detPositionInfoVect->size()))||((detPositionInfoVect->at(det_id))==NULL)){
        StringTools st;
        UtsusemiError(  _MessageTag+"Invalid detId ("+st.UInt4ToString(det_id)+")" );
    }

    std::vector<Double> *v = detPositionInfoVect->at( det_id );
    std::vector<double> pv = CalcPsdPixelPosition( det_id,pixelNo,numOfPixel );
    if (pv.empty()) return 0;

    std::vector<Double> v1( (v->size()+1),0.0 );
    v1[0] = numOfPixel;
    for (UInt4 i=0;i<v->size();i++){
        v1[i+1]=v->at(i);
    }

    return CalcPixelSolidAngle( &pv, &v1 );

}
//////////////////////////////////////////////////////////
double DetectorInfoEditorNeunet::
CalcPixelSolidAngle( std::vector<Double>* pv, std::vector<Double>* v1 ){
    /*
       pv = pixel position std::vector
       v1[0] = the number of pixels on a PSD
       v1[1] to v1[8] = PositionInfoVect ( read from XML file )
       ( v1[1],v1[2],v1[3] ) = P0 vec ( direction std::vector of detector )
       ( v1[4],v1[5],v1[6] ) = L std::vector (PSD direction and length)
       v1[7] = L0 : length between posi of P0 and origin of L vec
       v1[8] = diameter of PSD
     */

    if ((pv->size()<3)||(v1->size()<8)) {
        UtsusemiError( _MessageTag+"CalcPixelSolidAngle > parameters for position is invalid in DetectorInfo.xml " );
        return 0.0;
    }
    Double L2 = sqrt( pv->at(0)*pv->at(0) + pv->at(1)*pv->at(1) + pv->at(2)*pv->at(2) );
    Double l_u = sqrt( v1->at(4)*v1->at(4) + v1->at(5)*v1->at(5) + v1->at(6)*v1->at(6) )/v1->at(0);
    Double d_s = 1.0;
    if (v1->size()>8) d_s=l_u*v1->at(8);
    else UtsusemiWarning( _MessageTag+"WARNING :: CalcPixelSolidAngle > PSD width parameter is not defined in DetectorInfo.xml " );

    std::vector<Double> uv;
    uv.clear();
    for (UInt4 i=0;i<3;i++){
        uv.push_back(v1->at(i+4));
    }
    std::vector<Double> v = CrossVectorNorm( CrossVectorNorm( *pv, uv ), uv );
    //std::cout << _MessageTag << "################# CalcPixelSolidAngle end"<<std::endl;
    return -d_s*(pv->at(0)*v[0]+pv->at(1)*v[1]+pv->at(2)*v[2])/(L2*L2*L2);

}

//////////////////////////////////////////////////////////
std::vector<Double> DetectorInfoEditorNeunet::
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;
}

