import re
from typing import OrderedDict


def parse_region(regstr):
    """
    Parse the given region string into one of the following 4 cases:
    1. annulus
    2. pie (cxc)
    3. pie + annulus (ftools/xmm)
    4. other

    For the first 3 cases, the return is a dictionary like:
        { 'shape': 'pie', 'xc': 55, 'yc': 89,
          'radius_in': 50, 'radius_out': 100,
          'angle_begin': 30, 'angle_end': 120 }
    Otherwise, return None.
    """
    re_annulus = re.compile(r'^.*(?P<shape>annulus)\(\s*(?P<xc>[\d.-]+)\s*,\s*(?P<yc>[\d.-]+)\s*,\s*(?P<radius_in>[\d.-]+)\s*,\s*(?P<radius_out>[\d.-]+)\s*\).*$', re.I)
    re_pie_cxc = re.compile(r'^.*(?P<shape>pie)\(\s*(?P<xc>[\d.-]+)\s*,\s*(?P<yc>[\d.-]+)\s*,\s*(?P<radius_in>[\d.-]+)\s*,\s*(?P<radius_out>[\d.-]+)\s*,\s*(?P<angle_begin>[\d.-]+)\s*,\s*(?P<angle_end>[\d.-]+)\s*\).*$', re.I)
    re_pie_ft  = re.compile(r'^.*(?P<shape>pie)\(\s*(?P<xc>[\d.-]+)\s*,\s*(?P<yc>[\d.-]+)\s*,\s*(?P<angle_begin>[\d.-]+)\s*,\s*(?P<angle_end>[\d.-]+)\s*\).*$', re.I)
    m_annulus = re_annulus.match(regstr)
    m_pie_cxc = re_pie_cxc.match(regstr)
    m_pie_ft  = re_pie_ft.match(regstr)
    if m_pie_cxc is not None:
        # case 2: pie (cxc)
        region = OrderedDict([
            ('shape',       m_pie_cxc.group('shape').lower()),
            ('xc',          float(m_pie_cxc.group('xc'))),
            ('yc',          float(m_pie_cxc.group('yc'))),
            ('radius_in',   float(m_pie_cxc.group('radius_in'))),
            ('radius_out',  float(m_pie_cxc.group('radius_out'))),
            ('angle_begin', float(m_pie_cxc.group('angle_begin'))),
            ('angle_end',   float(m_pie_cxc.group('angle_end')))
        ])
    elif m_pie_ft is not None:
        # pie (ftools/xmm)
        if m_annulus is not None:
            # case 3: pie + annulus (ftools/xmm)
            region = OrderedDict([
                ('shape',       m_pie_ft.group('shape').lower()),
                ('xc',          float(m_pie_ft.group('xc'))),
                ('yc',          float(m_pie_ft.group('yc'))),
                ('radius_in',   float(m_annulus.group('radius_in'))),
                ('radius_out',  float(m_annulus.group('radius_out'))),
                ('angle_begin', float(m_pie_ft.group('angle_begin'))),
                ('angle_end',   float(m_pie_ft.group('angle_end')))
            ])
        else:
            region = None
    elif m_annulus is not None:
        # case 1: annulus
        region = OrderedDict([
            ('shape',      m_annulus.group('shape').lower()),
            ('xc',         float(m_annulus.group('xc'))),
            ('yc',         float(m_annulus.group('yc'))),
            ('radius_in',  float(m_annulus.group('radius_in'))),
            ('radius_out', float(m_annulus.group('radius_out')))
        ])
    else:
        region = None
    return region