import json
import pandas as pd
import io
import xlsxwriter as xlx

class Exporter :
    def __init__(self,_data):
        """
        The data is passed by syncfusion
        """
        self._data = _data
        self._sheets = _data['sheets'] if 'JSONData' not in _data else _data['JSONData']['sheets']
        self._stream = io.BytesIO()
        self._workbook = xlx.Workbook(self._stream)
    def _getColRowIndex(self,_label):
        """
        This function will return column/row given an excel specification for instance C1 -> 2,0
        """
        _ndxCol = []
        _ndxRow = []
        for xchar in _label.strip() :
            if xchar.isnumeric() :
                
                _ndxRow.append( xchar )
            else:
                _ndxCol.append( ord(xchar) -65)

        return sum(_ndxCol), int("".join(_ndxRow)) -1

    def _initData (self):
        
        self._charts = []
        for _info in self._sheets :
            _rows = _info['rows']
            _name = _info['name']   #-- sheet name
            _icol,_irow = self._getColRowIndex( _info.get('topLeftCell','A1'))
            _worksheet = self._workbook.add_worksheet(_name)

            for _item in _rows :
                cells = _item['cells']
                
                for _ndxcol in range(0, len(cells)) :
                    if not cells[_ndxcol] :
                        continue
                    if 'value' in cells[_ndxcol] :
                        _value = cells[_ndxcol]['value']
                        if 'formattedText' in cells[_ndxcol] :
                            _value = cells[_ndxcol]['formattedText']
                            
                        _worksheet.write(_irow, _icol + _ndxcol, _value) 

                    if 'chart' in cells[_ndxcol] :
                        for _chart in cells[_ndxcol]['chart'] :
                            offset = 0 if 'value' not in cells[_ndxcol] else 1
                            _xchar = chr( _ndxcol + _icol + 65 + offset)+str(_irow+1)
                            _meta = {'cell':_xchar, 'sheet_name':_name,'chart':_chart}
                            self._charts.append(_meta)
                        
                _irow += 1 # incrementing rows
    def _initCharts(self):
        for _meta in self._charts :
            _sheet = self._workbook.get_worksheet_by_name(_meta['sheet_name'])
            _chart = self._workbook.add_chart({'type':_meta['chart']['type'].lower()})
            if 'range' in _meta['chart'] :
                #
                # Analysis of the range expression in case we have more than one series
                _range  = _meta['chart']['range'].split('!')[-1]
            #     #
            #     #
                _series = _range.split(':')
                _lowerColIndex,_lowerRowIndex = self._getColRowIndex(_series[-1])
                _upperColIndex,_upperRowIndex = self._getColRowIndex(_series[0])
                
                if _upperColIndex == _lowerColIndex :
                    _xchar = chr(_upperColIndex + 65)
                    _chart.add_series({'values':_meta['chart']['range'],'name':f"{_meta['sheet_name']}!{_xchar}{_upperRowIndex+1}"})
                else:
                    for _i in range(_upperColIndex,_lowerColIndex + 1) :
                        _xchar = chr( _i + 65)
                        _range = f"{_meta['sheet_name']}!{_xchar}{_upperRowIndex+1}:{_xchar}{_lowerRowIndex+1}"
                        _chart.add_series({'values':_range,'name':f'{_meta["sheet_name"]}!{_xchar}{_upperRowIndex+1}'})
            _sheet.insert_chart(_meta['cell'],_chart) 
    def get(self):
        self._initData ()
        self._initCharts()
        self._workbook.close()
        self._stream.seek(0)
        return self._stream


#
# here is the interface to the calling code (in case it can)
def instance (_data) :
    return (Exporter(_data)).get()