import smtk
from . import utils

class CardFormat:
    '''Formatter for individual lines in ACE3P input files

    '''
    def __init__(self, keyword, item_path=None, fmt=None):
        '''Initialize formatting object

        '''
        self.keyword = keyword  # string or list (for expressions)
        # In some cases, the item name is the same as the keyword
        if item_path is None:
            self.item_path = keyword
        else:
            self.item_path = item_path
        self.format = fmt


    def write(self, scope, att, indent='  '):
        '''Writes line for input attribute

        Returns boolean indicating if line was writtern

        '''
        item = att.itemAtPath(self.item_path, '/')
        if item is None:
          print 'ERROR: item not found for attribute %s path %s' % \
            (att.name(), self.item_path)
          return False

        return self.write_item(scope, item, indent)


    def write_item(self, scope, item, indent='  '):
        '''Writes item's value

        '''
        # Check categories
        if not item.isMemberOf(scope.categories):
            return False

        # Write void type
        if item.type() == smtk.attribute.Item.VoidType:
            value = 'on' if item.isEnabled() else 'off'
            scope.output.write('%s%s: %s\n' % (indent, self.keyword, value))
            return True

        # Check enabled flag
        if not item.isEnabled():
            return False

        # Check for non-value items
        if not hasattr(item, 'value'):
            msg = 'item %s has no value (type %s)' % (item.name(), item.type())
            scope.logger.addError(msg)
            raise Exception(msg)

        # If value isn't set, skip it
        if not item.isSet(0):
            return False

        if hasattr(item, 'isExpression') and item.isExpression(0):
            return self.write_expression(scope, item, indent)

        if self.format is None:
            if item.type() == smtk.attribute.Item.DoubleType:
                self.format = '%g'
            else:
                self.format = '%s'

        # Check number of values
        value_string = ''
        if item.numberOfValues() > 1:
            value_string = utils.format_vector(item, self.format)
        else:
            value_string = self.format % item.value(0)

        output_string = '%s%s: %s\n' % (indent, self.keyword, value_string)
        scope.output.write(output_string)
        return True


    def write_expression(self, scope, item, indent='  '):
        '''Writes expression as two items

        Does NOT check categories or that item is set or enabled

        '''
        # Sanity check
        if not hasattr(item, 'expression'):
            print 'Invalid item type - does not support expressions', item.type()
            return False

        exp_att = item.expression(0)
        if not exp_att:
            msg = 'Expression not found for item %s' % item.name()
            scope.logger.addWarning(msg)
            return False

        pairs_group = exp_att.findGroup('ValuePairs')

        # Write  each variable in separate line
        for i in range(2):
            item = pairs_group.item(0, i)

            # Get name from keyword IF it is a list
            if isinstance(self.keyword, list) and len(self.keyword) > i:
                keyword = self.keyword[i]
            else:
                keyword = item.name()

            # Format values as space-delimited string
            n = item.numberOfValues()
            value_string_array = [''] * n
            for i in range(n):
                value_string_array[i] = item.valueAsString(i)
            value_string = ' '.join(value_string_array)

            line = '%s%s: %s\n' % (indent, keyword, value_string)
            scope.output.write(line)

        return True
