#!/usr/bin/env python
# -*- coding: utf-8 -*-
# generated by wxGlade 0.6 on Sun May 25 23:31:23 2008

# Copyright 2008 Martin Manns
# Distributed under the terms of the GNU General Public License
# generated by wxGlade 0.6 on Mon Mar 17 23:22:49 2008

# --------------------------------------------------------------------
# pyspread is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyspread is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyspread.  If not, see <http://www.gnu.org/licenses/>.
# --------------------------------------------------------------------

"""
_interfaces
===========

Provides:
---------
  1. CsvImport: Connects array datastructure with csv import module
  2. Clipboard: Clipboard access
"""

import csv

import wx

class CsvImport(object):
    """
    CSV file handling class
    
    Parameters:
    -----------
    filename: string
    \tFilename of CSV input file
    csvargs: dict
    \tArguments for csv import via the csv module
    
    Methods
    -------
    fill_target: Fills target with csv values.
    
    """
    def __init__(self, filename, csvargs):
        self.filename = filename
        self.csvargs = csvargs
        self.csvfile = None
    
    def _open_csv(self):
        """Opens the csv file named self.filename"""
        self.csvfile = open(self.filename, "r")
        return csv.reader(self.csvfile, **self.csvargs)

    def _close_csv(self):
        """Closes the csv file"""
        self.csvfile.close()
    
    def fill_target(self, target, key=(0, 0, 0)):
        """Fills target with csv values.
        
        The targets dimensions are assumed as defaulot limits
        unless specified otherwise.
        
        Parameters:
        -----------
        target: Mutable array or list with 2 dimensions
        \tIn this array, the csv values are stored
        
        key: 2-tuple, defaults to (0, 0)
        \tTop-left insertion position
        
        """
        
        error_log = []
        maxrows = len(target)
        top, left, table = key
        csv_it = self._open_csv()
        for row, values in enumerate(csv_it):
            if row != []:
                for col, ele in enumerate(values):
                    try:
                        target[row + top, col + left, table] = repr(ele)
                    except IndexError, err:
                        error_log.append([err, " at " + repr((col, ele))])
                if row > maxrows:
                    break
        self._close_csv()
        return error_log

# end of class CsvImport

class Clipboard(object):
    """Clipboard access
    
    Provides:
    ---------
    get_clipboard: Get clipboard content
    set_clipboard: Set clipboard content
    grid_paste: Inserts data into grid target
    
    """
    
    clipboard = wx.TheClipboard
    
    def _convert_clipboard(self, datastring=None, sep='\t'):
        """Converts data string to iterable.
        
        Parameters:
        -----------
        datastring: string, defaults to None
        \tThe data string to be converted. 
        \tself.get_clipboard() is called if set to None
        sep: string
        \tSeparator for columns in datastring
        
        """
        
        if datastring is None:
            datastring = self.get_clipboard()
        
        data_it = ((ele for ele in line.split(sep)) \
                            for line in datastring.splitlines())
        return data_it
        
    def get_clipboard(self):
        """Returns the clipboard text content"""
        
        textdata = wx.TextDataObject()
        if self.clipboard.Open():
            self.clipboard.GetData(textdata)
            self.clipboard.Close()
        else:
            wx.MessageBox("Can't open the clipboard", "Error")
        return textdata.GetText()
    
    def set_clipboard(self, data):
        """Writes data to the clipboard"""
        
        error_log = []
        
        textdata = wx.TextDataObject()
        try:
            textdata.SetText(data)
        except UnboundLocalError, err:
            error_log.append([err, "Error converting to string"])
        if self.clipboard.Open():
            self.clipboard.SetData(textdata)
            self.clipboard.Close()
        else:
            wx.MessageBox("Can't open the clipboard", "Error")
        return error_log
    
    def grid_paste(self, target, pos=(0, 0)):
        """Inserts data into target.
        
        The data in the clipboard has to be a whitespace separated
        2D matrix.
        
        Parameters:
        -----------
        target: Mutable array or list with 2 dimensions
        \tTarget array for data
        
        """
        error_log = []
        
        data_it = self._convert_clipboard()

        top, left, table = pos

        for row, values in enumerate(data_it):
            if row != []:
                for col, ele in enumerate(values):
                    if ele != '\b': # \b stands for omitted field
                        try:
                            target[row + top, col + left, table] = str(ele)
                        except IndexError, err:
                            error_log.append([err, " at " + repr((col, ele))])
        return error_log

# end of class Clipboard


def string_match(datastring, findstring, flags=None):
    """Returns True if findstring is found in datastring, otherwise False.
       Flags is a list of strings. Supported strings are:
       "MATCH_CASE": The case has to match for valid find
       "WHOLE_WORD": The word has to be surrounded by whitespace characters
                     if in the middle of the string
    """
    if flags is None:
        flags = []
    if "MATCH_CASE" not in flags:
        datastring = datastring.lower()
        findstring = findstring.lower()
    if findstring in datastring:
        if "WHOLE_WORD" in flags:
            findstringlength = len(findstring)
            try:
                if datastring.find(findstring) == 0 and \
                   datastring[findstringlength].isspace():
                    return 0
            except IndexError:
                if datastring == findstring: return 0
            try:
                if datastring.lstrip() == findstring and \
                   datastring[findstringlength + \
                   datastring.find(findstring)].isspace():
                    return datastring.find(findstring)
            except IndexError:
                if datastring.lstrip() == findstring: 
                    return datastring.find(findstring)
            for i, s in enumerate(datastring):
                try:
                    stringslice = datastring[i+1:i+1+findstringlength]
                    stringfound = (stringslice == findstring)
                except IndexError: 
                    stringfound = False
                if stringfound and s.isspace():
                    try:
                        if datastring[i+1+findstringlength].isspace():
                            return i + 1
                    except IndexError: pass
            try:
                if datastring.find(findstring) == len(datastring) - 1 and \
                   datastring[-findstringlength-1].isspace():
                    return len(datastring) - len(findstring) - 1
            except IndexError: pass
            return None
        else: # No "WHOLE_WORD"
            return datastring.find(findstring)
    return None
