from libcpp.map cimport map
from libcpp.pair cimport pair
from libcpp.vector cimport vector
from libcpp cimport bool
from libcpp.string cimport string
from libcpp.memory cimport unique_ptr

ctypedef int PdgId
ctypedef pair[PdgId,PdgId] PdgIdPair

cdef extern from "<sstream>" namespace "std":
    cdef cppclass ostringstream:
        ostringstream()
        string& str()
    cdef cppclass istringstream:
        istringstream()
        string& str(string&)

cdef extern from "Rivet/AnalysisHandler.hh" namespace "Rivet":
    cdef cppclass AnalysisHandler:
        void setCheckBeams(bool)
        void skipMultiWeights(bool)
        void matchWeightNames(string)
        void unmatchWeightNames(string)
        void setNominalWeightName(string)
        void setBootstrapFilename(string)
        void setNLOSmearing(double)

        AnalysisHandler& addAnalysis(string)
        vector[string] analysisNames()
        vector[string] stdAnalysisNames()
        vector[pair[string,size_t]] fillLayout()
        vector[bool] fillOutcomes()
        vector[double] fillFractions()
        # Analysis* analysis(string)
        void writeData_FILE "writeData" (string&) except +
        void writeData_OSTR "writeData" (ostringstream&, string&) except +
        void readData_FILE "readData" (string&, bool) except +
        void readData_ISTR "readData" (istringstream&, string&, bool) except +
        void loadAOs(vector[string]&, vector[double]&) except +
        void setCrossSection(double, double, bool)
        double nominalCrossSection()
        double nominalCrossSectionError()
        void finalize()
        void setFinalizePeriod(string, int)
        void mergeYODAs(vector[string]&, vector[string]&, vector[string]&, vector[string]&, vector[string]&, bool, bool)
        void merge(AnalysisHandler&)
        vector[string] getRawAOPaths() except +

        # Weight stream related methods
        vector[string] weightNames() except +
        bool haveNamedWeights() except +
        size_t numWeights() except +
        vector[double] weightSumWs() except +
        void setWeightCap(double) except +

        # MPI (de-)serialization
        vector[double] serializeContent(bool) except +
        void deserializeContent(vector[double]&, size_t) except +

cdef extern from "Rivet/Run.hh" namespace "Rivet":
    cdef cppclass Run:
        Run(AnalysisHandler)
        Run& setCrossSection(double) # For chaining?
        Run& setListAnalyses(bool)
        bool init(string, double) except + # $2=1.0
        bool openFile(string, double) except + # $2=1.0
        bool readEvent() except +
        #bool skipEvent() except +
        bool processEvent() except +
        bool finalize() except +
        size_t numEvents()

cdef extern from "Rivet/Analysis.hh" namespace "Rivet":
    cdef cppclass Analysis:
        vector[PdgIdPair]& requiredBeamIDs()
        vector[pair[double, double]] requiredBeamEnergies()
        vector[string] authors()
        vector[string] references()
        vector[string] keywords()
        vector[string] validation()
        bool reentrant()
        string name()
        string bibTeX()
        string bibKey()
        string collider()
        string description()
        string experiment()
        string inspireID()
        string spiresID()
        string runInfo()
        string status()
        string warning()
        string summary()
        string year()
        double luminosity()
        double luminosityfb()
        string refFile()
        string refMatch()
        string refUnmatch()
        string writerDoublePrecision()


# Might need to translate the following errors, although I believe 'what' is now
# preserved. But often, we need the exception class name.
#Error
#RangeError
#LogicError
#PidError
#InfoError
#WeightError
#UserError

cdef extern from "Rivet/AnalysisLoader.hh":
    vector[string] AnalysisLoader_analysisNames "Rivet::AnalysisLoader::analysisNames" ()
    vector[string] AnalysisLoader_allAnalysisNames "Rivet::AnalysisLoader::allAnalysisNames" ()
    map[string,string] AnalysisLoader_analysisNameAliases "Rivet::AnalysisLoader::analysisNameAliases" ()
    vector[string] AnalysisLoader_stdAnalysisNames "Rivet::AnalysisLoader::stdAnalysisNames" ()
    unique_ptr[Analysis] AnalysisLoader_getAnalysis "Rivet::AnalysisLoader::getAnalysis" (string)
    #
    vector[string] AnalysisLoader_analysisPlugins "Rivet::AnalysisLoader::analysisPlugins" ()
    vector[string] AnalysisLoader_searchAnalysisPlugins "Rivet::AnalysisLoader::searchAnalysisPlugins" ()
    void AnalysisLoader_setAnalysisPlugins "Rivet::AnalysisLoader::setAnalysisPlugins" (vector[string])
    void AnalysisLoader_loadFromAnalysisPlugins "Rivet::AnalysisLoader::loadFromAnalysisPlugins" ()


cdef extern from "Rivet/Tools/RivetPaths.hh" namespace "Rivet":
    vector[string] getAnalysisLibPaths()
    void setAnalysisLibPaths(vector[string])
    void addAnalysisLibPath(string)

    vector[string] getAnalysisDataPaths()
    void setAnalysisDataPaths(vector[string])
    void addAnalysisDataPath(string)
    string findAnalysisDataFile(string)

    vector[string] getAnalysisRefPaths()
    string findAnalysisRefFile(string)

    vector[string] getAnalysisInfoPaths()
    string findAnalysisInfoFile(string)

    vector[string] getAnalysisPlotPaths()
    string findAnalysisPlotFile(string)

cdef extern from "Rivet/Rivet.hh" namespace "Rivet":
    string version()

cdef extern from "Rivet/Tools/Logging.hh":
    void setLogLevel "Rivet::Log::setLevel" (string, int)

cdef extern from "Rivet/Tools/ProjectionTreePlotter.hh" namespace "Rivet":
    cdef cppclass ProjectionTreeGenerator:
        void setPath(string&)
        int generateProjTree(vector[string]&)
        int getProjTree(AnalysisHandler&)
        void writeProjTree()
        vector[pair[size_t,size_t]]& getEdges()
        vector[string]& getProjNames()

