cimport util
cdef class Estimate0D(AnalysisObject):
    """
    An Estimate0D, consisting of a central value and an error breakdown.
    """

    cdef c.Estimate0D* estptr(self) except NULL:
        return <c.Estimate0D *> self.ptr()

    def __init__(self, path="", title=""):
        cutil.set_owned_ptr(self, new c.Estimate0D(<string>path,
                                                 <string>title))

    def __repr__(self):
        val = self.val()
        #lo,hi = self.quadSum()
        return "<Estimate0D(value=%.2e) '%s'>" % (val, self.path())

    def clone(self):
        """None -> Estimate0D.
        Clone this Estimate0Dr."""
        return cutil.new_owned_cls(Estimate0D, self.estptr().newclone())

    def setVal(self, value):
       self.estptr().setVal(value)


    def setErr(self, *es):
       source = None
       es = list(es)
       if type(es[-1]) is str:
           source = es[-1]
           es = es[:-1]
       errs = es
       if source is None:
           source = ""
       #if isinstance(source, str):
       #    source = source.encode('utf-8')
       if len(errs) == 1:
           if not hasattr(errs[0], "__iter__"):
               self.estptr().setErr(util.read_symmetric(errs[0]), <string> source)
               return
           errs = errs[0]
       self.estptr().setErr(tuple(errs), <string> source)


    def set(self, val, errs, source = ""):
       self.setVal(val)
       self.setErr(errs, source)


    def reset(self):
        """
        () -> None

        Reset the Estimate0Ds to the unfilled state.
        """
        self.estptr().reset()

    def val(self):
       return self.estptr().val()

    def errDownUp(self, source = ""):
       return tuple(self.estptr().errDownUp(source))

    def err(self, source = ""):
       return tuple(self.estptr().err(source))

    def errNegPos(self, source = ""):
       return tuple(self.estptr().errNegPos(source))

    def errDown(self, source = ""):
       return self.estptr().errDown(source)

    def errUp(self, source = ""):
       return self.estptr().errUp(source)

    def errNeg(self, source = ""):
       return self.estptr().errNeg(source)

    def errPos(self, source = ""):
       return self.estptr().errPos(source)

    def relErrDownUp(self, source = ""):
       return tuple(self.estptr().relErrDownUp(source))

    def relErr(self, source = ""):
       return tuple(self.estptr().relErr(source))

    def relErrDown(self, source = ""):
       return self.estptr().relErrDown(source)

    def relErrUp(self, source = ""):
       return self.estptr().relErrUp(source)

    def quadSum(self, pat_match = ""):
       return tuple(self.estptr().quadSum(pat_match))

    def quadSumNeg(self, pat_match = ""):
       return self.estptr().quadSumNeg(pat_match)

    def quadSumPos(self, pat_match = ""):
       return self.estptr().quadSumPos(pat_match)

    def totalErr(self, pat_match = ""):
       return tuple(self.estptr().totalErr(pat_match))

    def relTotalErr(self, pat_match = ""):
       return tuple(self.estptr().relTotalErr(pat_match))

    def relTotalErrNeg(self, pat_match = ""):
       return self.estptr().relTotalErrNeg(pat_match)

    def relTotalErrPos(self, pat_match = ""):
       return self.estptr().relTotalErrPos(pat_match)

    def hasSource(self, str source):
       return self.estptr().hasSource(<string> source)

    ## In-place special methods

    def __iadd__(Estimate0D self, Estimate0D other):
        c.Estimate0D_iadd_Estimate0D(self.estptr(), other.estptr())
        return self

    def __isub__(Estimate0D self, Estimate0D other):
        c.Estimate0D_isub_Estimate0D(self.estptr(), other.estptr())
        return self

    def sources(self):
       return self.estptr().sources()

    def numErrs(self):
       return self.estptr().numErrs()

    def rmSource(self, str source):
      return self.estptr().rmSource(<string> source)

    def rmErrs(self):
      return self.estptr().rmErrs()

    def lengthContent(self, fixed_length = False):
        """Length of serialisaed data vector for MPI communication."""
        return self.estptr().lengthContent(fixed_length)

    def serializeContent(self, fixed_length = False):
        """Data serialisation for MPI communication."""
        self.estptr().serializeContent(fixed_length)

    def deserializeContent(self, data):
        """Data deserialisation for MPI communication."""
        cdef vector[double] cdata
        cdata = [ float(x) for x in data ]
        self.estptr().deserializeContent(cdata)

    def lengthMeta(self, skipPath = True, skipTitle = True):
        """Length of serialisaed meta-data vector for MPI communication."""
        return self.estptr().lengthMeta(skipPath, skipTitle)

    def serializeMeta(self, skipPath = True, skipTitle = True):
        """Meta-data serialisation for MPI communication."""
        self.estptr().serializeMeta(skipPath, skipTitle)

    def deserializeMeta(self, data, resetPath = False, resetTitle = False):
        """Meta-data deserialisation for MPI communication."""
        cdef vector[string] cdata
        cdata = [ str(x) for x in data ]
        self.estptr().deserializeMeta(cdata, resetPath, resetTitle)

    def scale(self, factor):
        self.estptr().scale(factor)

    def mkInert(self, str path = "", str source = ""):
        rtn = self.clone()
        rtn.setPath(path)
        if rtn.numErrs() == 1:
          try:
            rtn.renameSource("", source);
          except:
              pass
        return rtn

    def mkScatter(self, path = "", pat_match = ""):
        """None -> Scatter1D.

        Make a new Scatter1D."""
        s = <c.Scatter1D> self.estptr().mkScatter(path, pat_match)
        return cutil.new_owned_cls(Scatter1D, s.newclone())

    ## Unbound special methods
    def __add__(Estimate0D self, Estimate0D other):
        e = Estimate0D()
        cutil.set_owned_ptr(e, c.Estimate0D_add_Estimate0D(self.estptr(), other.estptr()))
        return e

    def __sub__(Estimate0D self, Estimate0D other):
        e = Estimate0D()
        cutil.set_owned_ptr(e, c.Estimate0D_sub_Estimate0D(self.estptr(), other.estptr()))
        return e

    def __div__(Estimate0D self, Estimate0D other):
        return self.divideBy(other)

    def __truediv__(Estimate0D self, Estimate0D other):
        return self.divideBy(other)

