#!/usr/bin/env python
"""Script to print a GCL model."""

import argparse
import sys

import gcl
from gcl import util

parser = argparse.ArgumentParser(description='Print a GCL model file.')
parser.add_argument('files', metavar='FILE', type=str, nargs='*',
                    help='Files to print')
parser.add_argument('-e', '--errors-only', dest='errors_only', action='store_true', default=False,
                    help='Only show errors')
parser.add_argument('-l', '--lowercase', dest='lowercase', action='store_true', default=False,
                    help='Don\'t recurse into variables starting with capital letters.')

args = parser.parse_args()


def printableKey(k):
  return not args.lowercase or ('a' <= k[0] <= 'z')


class PrintWalker(util.ExpressionWalker):
  def __init__(self, table, prefix_cells=[]):
    self.table = table
    self.prefix_cells = prefix_cells
    self.do_prefix = False

  def _newLine(self):
    self.table.feedLine()
    self.do_prefix = True

  def _maybePrintPrefix(self):
    if self.do_prefix:
      self.table.addAll(self.prefix_cells)
      self.do_prefix = False

  def _outline(self, path):
    return util.Cell('|  ' * len(path), 'cyan')

  def _printBullet(self, path):
    self._maybePrintPrefix()
    self.table.add(self._outline(path[:-1])
                       .write('+- ', 'cyan')
                       .write(path[-1]))

  def _printArrow(self):
    self.table.add(util.Cell('=>', 'cyan'))

  def _printRecordSeparator(self):
    self._maybePrintPrefix()
    self.table.add(util.Cell('----------', 'yellow'))
    self._newLine()

  def enterTuple(self, tuple, path):
    if path:
      if not printableKey(path[-1]):
        return False
      self._printBullet(path)
      self._newLine()

    return True

  def leaveTuple(self, tuple, path):
    pass

  def visitError(self, key_path, ex):
    self._printBullet(key_path)
    self._printArrow()
    self.table.add(util.Cell('<%s>' % ex, 'red'))
    self._newLine()

  def _printList(self, key_path, xs):
    if not len(xs):
      self.table.add(util.Cell('[]', 'yellow'))
      self._newLine()

    prefix = self.prefix_cells + [self._outline(key_path), util.Cell()]
    w2 = PrintWalker(self.table, prefix)
    for i, x in enumerate(xs):
      if isinstance(x, gcl.Tuple):
        if i:
          w2._printRecordSeparator()
        util.walk(x, w2)
      else:
        w2._printScalar([], x)

    if not w2.do_prefix:
      self._newLine()

  def _printScalar(self, key_path, value):
    self._maybePrintPrefix()
    if isinstance(value, list):
      self._printList(key_path, value)
    else:
      self.table.add(util.Cell(repr(value)))
      self._newLine()

  def visitScalar(self, key_path, value):
    if args.errors_only:
      return

    if not printableKey(key_path[-1]):
      return

    self._printBullet(key_path)
    self._printArrow()
    self._printScalar(key_path, value)


def print_model(model):
  table = util.ConsoleTable()
  util.walk(model, PrintWalker(table))
  table.printOut(sys.stdout)


if args.files:
  for filename in args.files:
    try:
      model = gcl.load(filename)
    except gcl.ParseError as e:
      print(e)
      break
    else:
      print_model(model)
else:
  try:
    model = gcl.loads(sys.stdin.read(), filename='<stdin>')
  except gcl.ParseError as e:
    print(e)
  else:
    print_model(model)
