from win32com.client import Dispatch
from excel_const import constants
import string
import xlChFormula
import sys, os

def squareUpRS( rs, pad='' ):
    '''make the input data list of lists such that each row is the same length
       add "pad" to short rows'''
    
    maxL = len(rs[0])
    minL = maxL
    for row in rs:
        L = len(row)
        maxL = max(maxL, L)
        minL = min(minL, L)
    
    #print 'in squareUpRS, maxL=',maxL,'  minL=',minL
    
    if minL<maxL:
        rs = list(rs)
        for i,row in enumerate(rs):
            #print i,rs[i]
            #padL = [pad]*(maxL-len(row))
            #print '   padL=',padL
            rs[i] = list(row) + [pad]*(maxL-len(row))
            #print i,rs[i]
    return rs
    
    
    

class ExcelWrap:
    numWkBooks = 0
    def __init__(self,xlsFile="", Visible=1):
        self.xlApp = Dispatch("Excel.Application")
        self.xlApp.Visible = Visible
        ExcelWrap.numWkBooks = ExcelWrap.numWkBooks + 1
            
        # I don't think the sheet and column lists should be mapped
        # (unfortunately, they are right now)
        self.sheetList = []
        self.chartList = []
        self.chartNColumns = []  
        self.chartNRows = []
        self.leaveOpen = 1
        self.nRows = 0
        self.nColumns = 0
        self.formula = xlChFormula.xlChFormula() # a scratch variable
        
        if len(xlsFile)>0: # opening an existing XLS file
            xlsFile = os.path.abspath(xlsFile) # Excel likes absolute path names
            self.xlApp.Workbooks.Open(xlsFile)
            self.initFromXLSFile()
            self.xlBook = None
        else:              # making a new XLS file
            self.xlBook = self.xlApp.Workbooks.Add()            
            self.xlSheet = self.xlApp.Sheets(1)
            self.sheetList.append( self.xlSheet )
    
    def closeQuietly(self):
        self.xlApp.DisplayAlerts = 0  # Allow Quick Close without Save Message
    
    def closeQuestion(self):
        self.xlApp.DisplayAlerts = 1  # Get Save Question When Closing


    def __del__(self):
        if (__name__ != "__main__") and (not self.leaveOpen):
            # i.e. only close if this is not a Self Test
            if self.xlApp != None: self.close()
            
    def getSheetNumberFromName(self, shtName='Sheet1'):
        '''get workbook sheet number from name'''
        ns=1
        isheet = 1 # 1-based index
        for i in range(1, self.xlApp.Sheets.Count+1):
            if self.xlApp.Sheets(i).Type == constants.xlWorksheet:
                if shtName==str(self.xlApp.Sheets(i).Name): ns = isheet
                #print 'sheet #%i = %s'%(isheet,self.xlApp.Sheets(i).Name)
                isheet += 1
                
        #print 'selected sheet =',ns
        return ns # for 1-based index
            
    def getChartSheetNumberUsingSheetData(self, datashtName='Sheet1'):
        '''get chart sheet number which uses data from sheet name'''
        ns = 0
        for i in range(1, self.xlApp.Sheets.Count+1):  #sheets use 1-based index
            try:  # check all sheets even if previous sheets raise an exception
                if self.xlApp.Sheets(i).Type != constants.xlWorksheet:
                    # must be a chart if not a worksheet
                    f = xlChFormula.xlChFormula( self.xlApp.Sheets(i).SeriesCollection(1).Formula)
                    # returns last chart which uses data from sheet
                    if datashtName==f.labelSht: ns = i
            except:
                pass
        #print datashtName, ns
        return ns
            
    def initFromXLSFile(self):
        '''initialize from existing XLS file.  
           (file has already been opened and assigned to self.xlApp)'''

        #print "now in initFromXLSFile"
        self.xlSheet = None
        self.chart = None
        
        for ns in range(1, self.xlApp.Sheets.Count+1):  #sheets use 1-based index
            try:
                #print "starting loop",ns
                if self.xlApp.Sheets(ns).Type == constants.xlWorksheet:
                    Ncolumns, Nrows = xlChFormula.getNcolumnsNrowsFromRange(\
                        self.xlApp.Sheets(ns).UsedRange.AddressLocal)
                        
                    # check that sheet has info in it and should be added to sheet list
                    if Ncolumns>0 and Nrows>0:
                        self.xlSheet = self.xlApp.Sheets(ns)
                        self.sheetList.append( self.xlSheet )
                        self.nRows = Nrows
                        self.nColumns = Ncolumns
                        
                        # chart and sheet lists are mapped
                        self.chartNColumns.append( self.nColumns )
                        self.chartNRows.append( self.nRows )
                        
                        #print "calling getChartSheetNumberUsingSheetData"
                        nc = self.getChartSheetNumberUsingSheetData(self.xlApp.Sheets(ns).Name)
                        #print "found chart for sheet",ns,"chart=",nc
                        #print "chart type =",self.xlApp.Sheets(nc).ChartType," =? ",constants.xlXYScatterLines
                        if (nc>0): ###/// and (self.xlApp.Sheets(nc).ChartType==constants.xlXYScatterLines):
                            #print "assigning chart for sheet",ns,"chart=",nc
                            self.chart = self.xlApp.Sheets(nc)
                            self.chartList.append( self.chart )
                        #else:
                        #    self.chartList.append( None )
                        
            except:
                pass

    def getRangeValueFromRowCol(self, ULrow=1, ULcol=1, LRrow=9, LRcol=9):
        cUL = self.formula.makeColLocation( NColumn=ULcol, NRow=ULrow)
        cLR = self.formula.makeColLocation( NColumn=LRcol, NRow=LRrow)
        return self.getRangeValue( cUL, cLR )

    def getRangeValue(self, ULcell='$A$1', LRcell='$D$5'):
        try:
            r = self.xlSheet.Range(ULcell, LRcell)
            return  r.Value 
        except:
            return ''

    def getCellValue(self, cell='$A$1'):
        try:
            r = self.xlSheet.Range(cell, cell)
            return str( r.Value )
        except:
            return ''

    def getRowColCellValue(self, NColumn=1, NRow=1):
        c = self.formula.makeColLocation( NColumn=NColumn, NRow=NRow)
        return self.getCellValue(c)    

    def getColumnName(self, NColumn=1):        
        if NColumn<=self.nColumns:
            #///cL = '$'+ self.formula.excelColLetter( NColumn )+ '$1'
            cL = self.formula.makeColLocation( NColumn=NColumn, NRow=1)
            r = self.xlSheet.Range(cL, cL)
            return str( r.Value )
        else:
            return 'None'

    def getAllColumnNames(self):
        cL = self.formula.makeColLocation( NColumn=self.nColumns, NRow=1)
        r = self.xlSheet.Range("$a$1", cL)
        return r.Value[0]
        
    def addNewSeries(self, NChart=1, NSheet=1, xColumn=1, yColumn=2):
        # use 1-based indeces for NChart and NSheet

        sh = self.sheetList[NSheet-1]
        ch = self.chartList[NChart-1]
        series = ch.SeriesCollection().NewSeries()
        Ncolumns, Nrows = xlChFormula.getNcolumnsNrowsFromRange( sh.UsedRange.AddressLocal )
        L = self.formula.makeColRange(NColumn=xColumn, fromRow=2, toRow=Nrows)
        rx = sh.Range(L)
        series.XValues = rx
        
        L = self.formula.makeColRange(NColumn=yColumn, fromRow=2, toRow=Nrows)
        ry = sh.Range(L)
        series.Values = ry
        
        cL = self.formula.makeColLocation( NColumn=yColumn, NRow=1)
        r = sh.Range(cL)
        series.Name = r
        
    def addNewSeriesToCurrentSheetChart(self, xColumn=1, yColumn=2):

        sh = self.xlSheet
        ch = self.chart
        series = ch.SeriesCollection().NewSeries()
        Ncolumns, Nrows = xlChFormula.getNcolumnsNrowsFromRange( sh.UsedRange.AddressLocal )
        L = self.formula.makeColRange(NColumn=xColumn, fromRow=2, toRow=Nrows)
        rx = sh.Range(L)
        series.XValues = rx
        
        L = self.formula.makeColRange(NColumn=yColumn, fromRow=2, toRow=Nrows)
        ry = sh.Range(L)
        series.Values = ry
        
        cL = self.formula.makeColLocation( NColumn=yColumn, NRow=1)
        r = sh.Range(cL)
        series.Name = r


    def changeSeriesOnChart(self, NChart=1, NSeries=1, NSheet=1, xColumn=1, yColumn=2):
        # use 1-based indeces for NChart and NSheet
        sh = self.sheetList[NSheet-1]
        ch = self.chartList[NChart-1]
        Ncolumns, Nrows = xlChFormula.getNcolumnsNrowsFromRange( sh.UsedRange.AddressLocal )
        L = self.formula.makeColRange(NColumn=xColumn, fromRow=2, toRow=Nrows)
        rx = sh.Range(L)
        ch.XYGroups(1).SeriesCollection(NSeries).XValues = rx
        
        L = self.formula.makeColRange(NColumn=yColumn, fromRow=2, toRow=Nrows)
        ry = sh.Range(L)
        ch.XYGroups(1).SeriesCollection(NSeries).Values = ry
        
        cL = self.formula.makeColLocation( NColumn=yColumn, NRow=1)
        r = sh.Range(cL)
        ch.SeriesCollection(NSeries).Name = r

    def changeSeriesXValuesColumn(self, NColumn=2, NSeries=1):
        if NColumn<=self.nColumns:
            L = self.formula.makeColRange(NColumn=NColumn, fromRow=2, toRow=self.nRows)
            r = self.xlSheet.Range(L)
            self.chart.XYGroups(1).SeriesCollection(NSeries).XValues = r
            self.labelXAxis( self.getAllXNames() )
            
            #///////////// Formula approach seems buggy            
            #self.formula.setFormula(self.chart.XYGroups(1).SeriesCollection(NSeries).Formula )
            #self.formula.setXColumn( col=NColumn, topRow=2, botRow=self.nRows, Sheet='')
            #self.chart.XYGroups(1).SeriesCollection(NSeries).Formula = self.formula.getFormula()

    def setAllXValueColumns(self, NColumn=1, ZeroBased=0):
        try:
            ns = 1
            c = NColumn
            if ZeroBased:c = c + 1
            while 1:
                L = self.formula.makeColRange(NColumn=c, fromRow=2, toRow=self.nRows)
                r = self.xlSheet.Range(L)
                self.chart.XYGroups(1).SeriesCollection(ns).XValues = r
                ns = ns + 1
        except:
            pass
        self.labelXAxis( self.getRowColCellValue( NColumn=c, NRow=1) )

    def changePlottedColumn(self, NColumn=2, NSeries=1):
        try:
            if NColumn<=self.nColumns:
                L = self.formula.makeColRange(NColumn=NColumn, fromRow=2, toRow=self.nRows)
                r = self.xlSheet.Range(L)
                self.chart.XYGroups(1).SeriesCollection(NSeries).Values = r

                cL = self.formula.makeColLocation( NColumn=NColumn, NRow=1)
                r = self.xlSheet.Range(cL)
                self.chart.SeriesCollection(NSeries).Name = r
                #////////// Formula approach seems buggy
                #self.formula.setFormula(self.chart.XYGroups(1).SeriesCollection(NSeries).Formula )
                #self.formula.setValColumn( col=NColumn, topRow=2, botRow=self.nRows, Sheet='')
                #self.formula.setLabel( col=NColumn, row=1, Sheet='')
                #self.chart.XYGroups(1).SeriesCollection(NSeries).Formula = self.formula.getFormula()
        except: pass
        
    def formatFocusedChart(self):

        self.chart.ChartType = constants.xlXYScatterLines
        self.chart.SizeWithWindow = 1

        self.chart.PlotArea.Interior.ColorIndex = constants.xlNone

        self.chart.HasTitle = 1  # Need to enable title before setting text
        self.chart.Axes( constants.xlCategory, constants.xlPrimary).HasTitle = 1
        
        self.chart.Axes( constants.xlValue, constants.xlPrimary).HasTitle = 1

        self.chart.Axes(1).HasMajorGridlines = 1  # turn on grid for x axis
        self.chart.Axes(1).MajorGridlines.Border.LineStyle = constants.xlDot  # make grid style dots
        self.chart.Axes(2).MajorGridlines.Border.LineStyle = constants.xlDot  # make grid style dots
    

    def makeNewChartOfPlottedColumns(self, cols=(2,), ZeroBased=0, chartName='' ):
        '''use cols tuple to set all plotted columns
        if Number of Columns is wrong, correct'''        
        
        self.chart = self.xlApp.Charts.Add()
        self.chartList.append( self.chart )
        self.chartNColumns.append( self.nColumns )
        self.chartNRows.append( self.nRows )
        
        self.formatFocusedChart()

        self.setAllPlottedColumns( cols=cols, ZeroBased=ZeroBased ,chartName=chartName)
        

    def setAllPlottedColumns(self, cols=(2,), ZeroBased=0 , chartName=''):
        '''use cols tuple to set all plotted columns
        if Number of Columns is wrong, correct'''
        if len(cols)>0: self.setNumberOfPlotCurves( len(cols) )
        ns = 1
        name = ''
        for c in cols:
            if ZeroBased:c = c + 1
            self.changePlottedColumn(NColumn=c, NSeries=ns)
            ns = ns + 1
            if len(name)>0: name = name + ", "
            name = name + str( self.getColumnName(c) )
        self.labelPrimaryYAxis(yLabel=name)
        self.labelXAxis( self.getColumnName(1) )
        if len(chartName)>0: self.chart.Location(Where=1, Name=chartName)

    def focusSheet(self, N):
        '''use 1-based index to Sheets'''
        #print 'focusing on sheet #',N
        self.xlSheet = self.sheetList[N-1]
        #self.chart = self.chartList[N-1]
        #self.nColumns = self.chartNColumns[N-1]
        #self.nRows = self.chartNRows[N-1]
        self.xlSheet.Activate()
        
    def focusSheetByName(self, shtName='Sheet1'):
        N = self.getSheetNumberFromName( shtName=shtName)
        self.focusSheet(N)

    def focusChart(self, N):
        '''use 1-based index to Charts'''
        self.xlSheet = self.sheetList[N-1]
        self.chart = self.chartList[N-1]
        self.nColumns = self.chartNColumns[N-1]
        self.nRows = self.chartNRows[N-1]
        self.chart.Activate()

    def labelPrimaryYAxis(self, yLabel="Vertical Axis"):        
        self.chart.Axes( constants.xlValue, constants.xlPrimary).HasTitle = 1
        self.chart.Axes( constants.xlValue, constants.xlPrimary).AxisTitle.Characters.Text = yLabel

    def getAllXNames(self):
        xLabels = {}
        allXNames = ''
        try:
            ns = 1
            while 1:
                self.formula.setFormula(self.chart.XYGroups(1).SeriesCollection(ns).Formula)
                ns = ns + 1
                xLabels[self.getCellValue( cell=self.formula.labelLoc )] = 1
        except:
            pass
        for k in xLabels.keys():
            if len(allXNames)>0:allXNames = allXNames + ', '
            allXNames = allXNames + k
        return allXNames


    def labelXAxis(self, xLabel="Horizontal Axis"):
        self.chart.Axes( constants.xlCategory, constants.xlPrimary).HasTitle = 1
        self.chart.Axes( constants.xlCategory, constants.xlPrimary).AxisTitle.Characters.Text = xLabel

    def changePlotTitle(self, title="Data from Python Script"):
        self.chart.HasTitle = 1  # Need to enable title before setting text
        self.chart.ChartTitle.Characters.Text = title

    def setPlotTitleSize(self, pointSize=20, bold=0):
        self.chart.HasTitle = 1  # Need to enable title before setting text
        self.chart.ChartTitle.Characters.Font.Size = pointSize
        self.chart.ChartTitle.Characters.Font.Bold = bold
            
        
    def putSeriesOnSecondary(self, J, y2Label=""):
        '''use 1-based index to Sheets'''
        try:
            self.chart.SeriesCollection(J).AxisGroup = constants.xlSecondary
            if len(y2Label)>0:
                self.chart.Axes( constants.xlValue, constants.xlSecondary).HasTitle = 1
                self.chart.Axes( constants.xlValue, constants.xlSecondary).AxisTitle.Characters.Text = y2Label
        except:
            pass

    def putSeriesOnPrimary(self, J):
        '''use 1-based index to Sheets'''
        try:
            self.chart.SeriesCollection(J).AxisGroup = constants.xlPrimary
        except:
            pass

    def close(self):
        if self.xlBook != None:
            self.xlApp.DisplayAlerts=0 # Allow Quick Close without Save Message
            self.xlBook.Close()
            self.xlBook = None
            self.xlApp.DisplayAlerts=1
        ExcelWrap.numWkBooks = ExcelWrap.numWkBooks - 1
        if ExcelWrap.numWkBooks==0: self.xlApp.Quit()
        self.xlApp = None

    def setLineStyle(self, NSeries=1, style=1):
        if style==0: s =  constants.xlLineStyleNone
        elif style==1: s = constants.xlContinuous
        elif style==2: s = constants.xlDash 
        elif style==3: s = constants.xlDashDot  
        elif style==4: s = constants.xlDashDotDot
        elif style==5: s = constants.xlDot  
        elif style==6: s = constants.xlDouble
        elif style==7: s = constants.xlSlantDashDot
        else:s = constants.xlContinuous

        try:
            self.chart.SeriesCollection(NSeries).Border.LineStyle = s
            return 1
        except:
            return 0

    def setLineStyles(self, style=1):
        N = 1
        while self.setLineStyle(NSeries=N, style=style):
            N = N + 1

    def setLineThickness(self, NSeries=1, thickness=1):
        t=constants.xlMedium
        if thickness<=0:
            return self.setLineStyle( NSeries=NSeries, style=0)
        elif thickness==1: t=constants.xlHairline
        elif thickness==2: t=constants.xlThin
        elif thickness==3: t=constants.xlMedium
        else:              t=constants.xlThick
        try:
            self.setLineStyle( NSeries=NSeries, style=1)
            self.chart.SeriesCollection(NSeries).Border.Weight = t
            return 1
        except:
            return 0

    def setLineThicknesses(self, thickness=1):
        N = 1
        while self.setLineThickness(NSeries=N, thickness=thickness):
            N = N + 1

    def setSeriesColorIndex(self, NSeries=1, colorIndex=1):
        try:
            self.chart.SeriesCollection(NSeries).Border.ColorIndex = colorIndex
            if self.chart.SeriesCollection(NSeries).MarkerStyle != constants.xlMarkerStyleNone:
                self.chart.SeriesCollection(NSeries).MarkerBackgroundColorIndex = colorIndex
                self.chart.SeriesCollection(NSeries).MarkerForegroundColorIndex = colorIndex
            return 1
        except:
            return 0

    def setSeriesColor(self, NSeries=1, red=255, green=0, blue=0):
        try:
            RevRGB= int(red) + int(green * 256) + int(blue * 65536)

            self.chart.SeriesCollection(NSeries).Border.Color = RevRGB
            if self.chart.SeriesCollection(NSeries).MarkerStyle != constants.xlMarkerStyleNone:
                self.chart.SeriesCollection(NSeries).MarkerBackgroundColor = RevRGB
                self.chart.SeriesCollection(NSeries).MarkerForegroundColor = RevRGB
            #print 'RevRGB',RevRGB
            return 1
        except:
            return 0


    def setMarkerSize(self, NSeries=1, size=4):
        try:
            self.chart.SeriesCollection(NSeries).MarkerSize = size
            return 1
        except:
            return 0

    def setMarkerSizes(self, size=4):
        N = 1
        while self.setMarkerSize(NSeries=N, size=size):
            N = N + 1


    def turnMarkerOnOff(self, NSeries=1, showPoints=0):
        try:
            if showPoints:
                self.chart.SeriesCollection(NSeries).MarkerStyle = constants.xlMarkerStyleAutomatic
            else:
                self.chart.SeriesCollection(NSeries).MarkerStyle = constants.xlMarkerStyleNone
            return 1
        except:
            return 0

    def turnMarkersOnOff(self, showPoints=0):
        N = 1
        while self.turnMarkerOnOff(NSeries=N, showPoints=showPoints):
            N = N + 1
    
    def setXScaleType(self, log=1):
        if log:
            self.chart.Axes(1).ScaleType = constants.xlLogarithmic
            #self.chart.Axes(1).AxisBetweenCategories = 1
            self.chart.Axes(1).MinorTickMark = constants.xlTickMarkCross
            self.chart.Axes(1).HasMinorGridlines = 1  # turn on grid for x axis
            self.chart.Axes(1).MinorGridlines.Border.LineStyle = constants.xlDot  # make grid style dots
            self.chart.Axes(1).MajorGridlines.Border.LineStyle = constants.xlContinuous
        else:
            self.chart.Axes(1).ScaleType = constants.xlScaleLinear
    
    def setYScaleType(self, log=1):
        if log:
            self.chart.Axes(2).ScaleType = constants.xlLogarithmic
            #self.chart.Axes(2).AxisBetweenCategories = 1
            self.chart.Axes(2).MinorTickMark = constants.xlTickMarkCross
            self.chart.Axes(2).HasMinorGridlines = 1  # turn on grid for x axis
            self.chart.Axes(2).MinorGridlines.Border.LineStyle = constants.xlDot  # make grid style dots
            self.chart.Axes(2).MajorGridlines.Border.LineStyle = constants.xlContinuous
        else:
            self.chart.Axes(2).ScaleType = constants.xlScaleLinear
    
    def setXrange(self, xmin=1.0, xmax=10.0):
        self.chart.Axes(1).MinimumScale=xmin
        self.chart.Axes(1).MaximumScale=xmax
    
    def setYrange(self, ymin=1.0, ymax=10.0):
        self.chart.Axes(2).MinimumScale=ymin
        self.chart.Axes(2).MaximumScale=ymax

        
    def setYrangeOnSecondary(self, ymin=1.0, ymax=10.0):
        self.chart.Axes(constants.xlValue, constants.xlSecondary).MinimumScale=ymin
        self.chart.Axes(constants.xlValue, constants.xlSecondary).MaximumScale=ymax


    def addTextBox(self,text='comment',left=100,top=100, width=50, height=50, 
        border=3, auto=1, transparency=0.3, isBold=0, fontSize=0):
        tb = self.chart.TextBoxes().Add(left,top,width,height)
        tb.Text=text[:255] # try limiting length to prevent errors
        tb.Border.Weight=border
        if isBold:
            tb.Font.IsBold = 1
        if fontSize:
            tb.Font.Size = fontSize
        if auto:
            tb.AutoSize=True
            tb.Interior.Color = constants.xlColorIndexAutomatic
        
            w = self.chart.PlotArea.Width
            h = self.chart.PlotArea.Height
        
            tb.Left = int( w/4)
            tb.Top = int( h/4 )
            
        tb.ShapeRange.Fill.Transparency = transparency
        
        
    def setNumberOfPlotCurves(self, NCurves=1):            
        pRange = self.xlSheet.Range('$A$1', self.xlSheet.Cells(self.nRows, NCurves+1))
        self.chart.SetSourceData( pRange, constants.xlColumns )

    def makeChart(self, rs, title="Data From Python", nCurves = 1,
                  sheetName="",chartName="",  showPoints=1, showLegend=1,
                  yLabel="Vertical Axis", xLabel="Horizontal Axis"):
        '''make Excel Chart from rs
        rs is a tuple of tuples, or a list of lists
        Top row of titles, then rows of data'''
        if len(self.chartList)>0:
            self.xlSheet = self.xlApp.Sheets.Add()
            self.sheetList.append( self.xlSheet )
        if len(sheetName)>0:self.xlSheet.Name = sheetName
    
        rs = squareUpRS( rs, pad='' )

        self.nRows = len(rs)
        self.nColumns = len(rs[0])
        cRange = self.xlSheet.Range('$A$1', self.xlSheet.Cells(self.nRows, self.nColumns))
        cRange.Value = rs
        
        self.chart = self.xlApp.Charts.Add()
        self.chartList.append( self.chart )
        self.chartNColumns.append( self.nColumns )
        self.chartNRows.append( self.nRows )
        if len(chartName)>0: self.chart.Location(Where=1, Name=chartName)

        self.chart.ChartType = constants.xlXYScatterLines
        self.chart.SizeWithWindow = 1

        if self.nColumns>nCurves+1:  # if number of curves is set, use it.
            pRange = self.xlSheet.Range('$A$1', self.xlSheet.Cells(self.nRows, nCurves+1))
        else:                     # otherwise plot everything
            pRange = cRange
        self.chart.SetSourceData( pRange, constants.xlColumns )
        self.chart.PlotArea.Interior.ColorIndex = constants.xlNone

        self.chart.HasTitle = 1  # Need to enable title before setting text
        self.chart.ChartTitle.Characters.Text = title
        
        if len(xLabel)>0:
            self.chart.Axes( constants.xlCategory, constants.xlPrimary).HasTitle = 1
            self.chart.Axes( constants.xlCategory, constants.xlPrimary).AxisTitle.Characters.Text = xLabel
        
        if len(yLabel)>0:
            self.chart.Axes( constants.xlValue, constants.xlPrimary).HasTitle = 1
            self.chart.Axes( constants.xlValue, constants.xlPrimary).AxisTitle.Characters.Text = yLabel

        self.chart.Axes(1).HasMajorGridlines = 1  # turn on grid for x axis
        self.chart.Axes(1).MajorGridlines.Border.LineStyle = constants.xlDot  # make grid style dots
        self.chart.Axes(2).MajorGridlines.Border.LineStyle = constants.xlDot  # make grid style dots
    
        if not showPoints: self.turnMarkersOnOff(showPoints=0)
        if not showLegend: self.chart.HasLegend = 0  # set Legend On or Off

    def makeDataSheet(self, rs, sheetName="DataSheet", autoFit=1, rowFormatL=None,
        textFont='', textFontSize=None):
        '''make Excel Data Sheet from rs
        rs is a tuple of tuples, or a list of lists
        Top row of titles, then rows of data'''
        self.xlSheet = self.xlApp.Sheets.Add()
        self.sheetList.append( self.xlSheet )
        if len(sheetName)>0:self.xlSheet.Name = sheetName
            
        rs = squareUpRS( rs, pad='' )
            
        
        self.nRows = len(rs)
        self.nColumns = len(rs[0])
        
        # get rid of any equals signs as 1st letter of string
        for i in range( self.nRows ):
            for j in range( self.nColumns ):
                try:
                    if rs[i][j][0]=='=':
                        rs[i][j] = "'" + str(rs[i][j])
                except:
                    pass
                        
        
        cRange = self.xlSheet.Range('$A$1', self.xlSheet.Cells(self.nRows, self.nColumns))
        cRange.Value = rs
        
        if textFont:
            cRange.Font.Name = textFont
            
        if textFontSize:
            cRange.Font.Size = textFontSize
        
        if autoFit:
            cRange.Columns.AutoFit()
            
        #cRange.NumberFormat = "0.00"
        if rowFormatL:
            for i,rowFormat in enumerate( rowFormatL ):
                if rowFormat:
                    N = i+1
                    cLR = self.formula.makeColLocation( NColumn=self.nColumns, NRow=N)
                    rowRange = self.xlSheet.Range('$A$%i'%N, cLR)
                    rowRange.NumberFormat = rowFormat
                    #print '$A$%i'%N, rowFormat
                

    def setRangeOfDataSheet(self, rs, sheetName="DataSheet", upperLeft='$A$1'):
        '''add to Excel Data Sheet from rs
        rs is a tuple of tuples, or a list of lists
        Top row of titles, then rows of data'''
        self.focusSheetByName(shtName=sheetName)
        
        rs = squareUpRS( rs, pad='' )
        
        ucol, urow = xlChFormula.getNcolNrow( cell=upperLeft)
        lcol = len(rs[0]) + ucol - 1
        lrow = len(rs) + urow - 1

        cLR = self.formula.makeColLocation( NColumn=lcol, NRow=lrow)
        
        #self.nRows = len(rs)
        #self.nColumns = len(rs[0])
        cRange = self.xlSheet.Range(upperLeft, cLR)
        cRange.Value = rs


    def setRangeOnCurrentSheet(self, rs, upperLeft='$A$1'):
        '''add to Excel Data Sheet from rs
        rs is a tuple of tuples, or a list of lists
        Top row of titles, then rows of data'''
        
        rs = squareUpRS( rs, pad='' )
        
        ucol, urow = xlChFormula.getNcolNrow( cell=upperLeft)
        lcol = len(rs[0]) + ucol - 1
        lrow = len(rs) + urow - 1

        cLR = self.formula.makeColLocation( NColumn=lcol, NRow=lrow)
        
        #self.nRows = len(rs)
        #self.nColumns = len(rs[0])
        cRange = self.xlSheet.Range(upperLeft, cLR)
        cRange.Value = rs
        

    def pageSetupForSheet(self, landscape=0, fitWidth=0, fitHeight=0, marginInches=0.0):
        '''use active sheet'''
        #self.xlSheet = self.sheetList[N-1]
        #self.xlSheet.Activate()
        if fitWidth:
            self.xlSheet.PageSetup.FitToPagesWide = fitWidth
        if fitHeight:
            self.xlSheet.PageSetup.FitToPagesTall = fitHeight
        
        if landscape:
            self.xlSheet.PageSetup.Orientation = constants.xlLandscape
        else:
            self.xlSheet.PageSetup.Orientation = constants.xlPortrait
        self.xlSheet.PageSetup.Zoom = False
        
        if marginInches > 0.0:
            self.xlSheet.PageSetup.LeftMargin = self.xlApp.InchesToPoints(marginInches)  
            self.xlSheet.PageSetup.RightMargin = self.xlApp.InchesToPoints(marginInches)  
            self.xlSheet.PageSetup.TopMargin = self.xlApp.InchesToPoints(marginInches)  
            self.xlSheet.PageSetup.BottomMargin = self.xlApp.InchesToPoints(marginInches)  
        

if __name__ == "__main__": #Self Test
    xl = ExcelWrap()
    rs = ( ("x", "y", "Zee","Queue"), (1,1,1,1,1,1), (2,2,3,4), (3,3,5,8) )
    rs = squareUpRS( rs, pad='xxx' )
    
    xl.makeChart(rs, title="Now is the time for First Things",nCurves = 3,
                 chartName="First Chart",
                 sheetName="First Dataset",
                 yLabel="Vertical Axis", xLabel="Horizontal Axis")
    rs = ( ("A", "B", "Cee", "Dee"), (11,33,33,33), (21,21,25,30), (31,11,21,25) )
    xl.makeChart(rs, title="This is a Second Plot",nCurves = 3,
                 chartName="Second Chart", showPoints=0, showLegend=0,
                 sheetName="Second Dataset",
                 yLabel="Vertical Axis", xLabel="Horizontal Axis")
    xl.focusChart(1)
    xl.putSeriesOnSecondary(1, y2Label="Second Y Axis")
    xl.putSeriesOnSecondary(2)
    xl.putSeriesOnPrimary(1)
    xl.labelXAxis("Whole New X Axis Label")
    xl.labelPrimaryYAxis("Whole New Y Axis Label")
    xl.setLineThickness(NSeries=1, thickness=1)
    xl.setLineThickness(NSeries=2, thickness=2)
    xl.setLineThickness(NSeries=3, thickness=3)
    xl.setMarkerSize( NSeries=1, size=4)
    xl.setMarkerSize( NSeries=2, size=6)
    xl.setMarkerSize( NSeries=3, size=8)
    xl.xlApp.DisplayAlerts = 0  # Allow Quick Close without Save Message
    xl.setLineStyle(NSeries=1, style=0)
    
    xl.setSeriesColorIndex(NSeries=1, colorIndex=1)
    #xl.setSeriesColorIndex(NSeries=2, colorIndex=22)
    xl.setSeriesColor( NSeries=2, red=0, green=255, blue=0)
    xl.setSeriesColor( NSeries=3, red=255, green=0, blue=0)
    text='''abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxy'''
    xl.addTextBox(text=text)
    xl.setXrange( 1.0, 3.0)
    xl.setYrange( 1.0, 5.0)
    