# encoding: utf-8

"""
Series-related oxml objects.
"""

from __future__ import absolute_import, print_function, unicode_literals

from ..simpletypes import XsdUnsignedInt
from ..xmlchemy import (
    BaseOxmlElement, OneAndOnlyOne, RequiredAttribute, ZeroOrOne
)


class CT_SeriesComposite(BaseOxmlElement):
    """
    ``<c:ser>`` custom element class. Note there are several different series
    element types in the schema, such as ``CT_LineSer`` and ``CT_BarSer``,
    but they all share the same tag name. This class acts as a composite and
    depends on the caller not to do anything invalid for a series belonging
    to a particular plot type.
    """
    idx = OneAndOnlyOne('c:idx')
    order = OneAndOnlyOne('c:order')
    tx = ZeroOrOne('c:tx')      # provide override for _insert_tx()
    spPr = ZeroOrOne('c:spPr')  # provide override for _insert_spPr()
    invertIfNegative = ZeroOrOne('c:invertIfNegative')  # provide _insert..()
    cat = ZeroOrOne('c:cat', successors=(
        'c:val', 'c:smooth', 'c:shape', 'c:extLst'
    ))
    val = ZeroOrOne('c:val', successors=('c:smooth', 'c:shape', 'c:extLst'))
    smooth = ZeroOrOne('c:smooth', successors=('c:extLst',))

    @property
    def val_pts(self):
        """
        The sequence of ``<c:pt>`` elements under the ``<c:val>`` child
        element, ordered by the value of their ``idx`` attribute.
        """
        val_pts = self.xpath('./c:val//c:pt')
        return sorted(val_pts, key=lambda pt: pt.idx)

    def _insert_invertIfNegative(self, invertIfNegative):
        """
        invertIfNegative has a lot of successors and they vary depending on
        the series type, so easier just to insert it "manually" as it's close
        to a required element.
        """
        if self.spPr is not None:
            self.spPr.addnext(invertIfNegative)
        elif self.tx is not None:
            self.tx.addnext(invertIfNegative)
        else:
            self.order.addnext(invertIfNegative)
        return invertIfNegative

    def _insert_spPr(self, spPr):
        """
        spPr has a lot of successors and it varies depending on the series
        type, so easier just to insert it "manually" as it's close to a
        required element.
        """
        if self.tx is not None:
            self.tx.addnext(spPr)
        else:
            self.order.addnext(spPr)
        return spPr

    def _insert_tx(self, tx):
        self.order.addnext(tx)
        return tx


class CT_StrVal_NumVal_Composite(BaseOxmlElement):
    """
    ``<c:pt>`` element, can be either CT_StrVal or CT_NumVal complex type.
    Using this class for both, differentiating as needed.
    """
    v = OneAndOnlyOne('c:v')
    idx = RequiredAttribute('idx', XsdUnsignedInt)

    @property
    def value(self):
        """
        The float value of the text in the required ``<c:v>`` child.
        """
        return float(self.v.text)

@@ -663,210 +663,492 @@
     
-idx = OneAndOnlyOne('c:idx')%0A    order = OneAndOnlyOne('c:order')%0A    tx = ZeroOrOne('c:tx')      # provide override for _insert_tx()%0A    spPr = ZeroOrOne('c:spPr')  # provide override for _insert_spPr(
+_tag_seq = (%0A        'c:idx', 'c:order', 'c:tx', 'c:spPr', 'c:invertIfNegative',%0A        'c:pictureOptions', 'c:marker', 'c:explosion', 'c:dPt', 'c:dLbls',%0A        'c:trendline', 'c:errBars', 'c:cat', 'c:val', 'c:xVal', 'c:yVal',%0A        'c:shape', 'c:smooth', 'c:bubbleSize', 'c:bubble3D', 'c:extLst'%0A    )%0A    idx = OneAndOnlyOne('c:idx')%0A    order = OneAndOnlyOne('c:order')%0A    tx = ZeroOrOne('c:tx', successors=_tag_seq%5B3:%5D)%0A    spPr = ZeroOrOne('c:spPr', successors=_tag_seq%5B4:%5D
 )%0A  
@@ -1174,24 +1174,33 @@
 = ZeroOrOne(
+%0A        
 'c:invertIfN
@@ -1211,31 +1211,38 @@
 ive'
-)  # provide _insert..(
+, successors=_tag_seq%5B5:%5D%0A    
 )%0A  
@@ -1283,66 +1283,21 @@
 ors=
-(%0A        'c:val', 'c:smooth', 'c:shape', 'c:extLst'%0A    )
+_tag_seq%5B13:%5D
 )%0A  
@@ -1338,43 +1338,21 @@
 ors=
-('c:smooth', 'c:shape', 'c:extLst')
+_tag_seq%5B14:%5D
 )%0A  
@@ -1399,22 +1399,39 @@
 ors=
-('c:extLst',))
+_tag_seq%5B18:%5D)%0A    del _tag_seq
 %0A%0A  
@@ -1732,982 +1732,8 @@
 x)%0A%0A
-    def _insert_invertIfNegative(self, invertIfNegative):%0A        %22%22%22%0A        invertIfNegative has a lot of successors and they vary depending on%0A        the series type, so easier just to insert it %22manually%22 as it's close%0A        to a required element.%0A        %22%22%22%0A        if self.spPr is not None:%0A            self.spPr.addnext(invertIfNegative)%0A        elif self.tx is not None:%0A            self.tx.addnext(invertIfNegative)%0A        else:%0A            self.order.addnext(invertIfNegative)%0A        return invertIfNegative%0A%0A    def _insert_spPr(self, spPr):%0A        %22%22%22%0A        spPr has a lot of successors and it varies depending on the series%0A        type, so easier just to insert it %22manually%22 as it's close to a%0A        required element.%0A        %22%22%22%0A        if self.tx is not None:%0A            self.tx.addnext(spPr)%0A        else:%0A            self.order.addnext(spPr)%0A        return spPr%0A%0A    def _insert_tx(self, tx):%0A        self.order.addnext(tx)%0A        return tx%0A%0A
 %0Acla

refactor CT_SeriesComposite