#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
#-------------------------------python------------------------pykig.py--#
#                                                                       #
#                          Da Python a Kig                              #
#                                                                       #
#--Maurizio Paolini-Daniele Zambelli-----------------------------2005---#
#
# (GPL license)

version="0.2.11"

#####
# Type constant
#####
TI=type(0)
TF=type(0.)
TS=type("")
TT=type((0, 0))

#####
# Constants: Point Style, Line Style, defaults values...
#####
PS=("Round", "RoundEmpty", "Rectangular", "RectangularEmpty", "Cross")
LS=("SolidLine", "DashLine", "DashDotLine", "DashDotDotLine", "DotLine")
KIGTRUE="true"
KIGFALSE="false"
DEFWIDTH=-1
DEFCOLOR="#0000ff"
DEFNAME="none"
PROPERTY_INI="Property which"
OBJECT_INI="Object type"
PROPERTY_END="Property"
OBJECT_END="Object"
DICT=(("&","&amp;"), ("<","&lt;"), (">","&gt;"),
      ("à","Ã "), ("è","Ã¨"), ("ì","Ã¬"), ("ò","Ã²"), ("ù","Ã¹"), ("é","Ã©"))

#
# this is a trick to allow definitions like  "p=Point(0,0,HIDDEN)"
# 
HIDDEN=KIGFALSE
VISIBLE=KIGTRUE

#####
# Validation parameters
#####

def parameter(val, defval):
  if val==None: return defval
  else:         return val
  
def validshown(shown):
  if shown==KIGTRUE or shown==KIGFALSE: return shown

def validwidth(width):
  if type(width)==TI: return width

def validpointstyle(ps):
  if ps in PS: return ps

def validname(name):
  if type(name)==TS: return name

def validlinestyle(ls):
  if ls in LS: return ls

def validcolor(color):
  if type(color)==TS: return color

#####
# if as function
#####

def rif(condition, val1, val2):
  """Return val1 if condition is True else return val2."""
  if condition: return val1
  else:         return val2

#####
# Force some Python variables as kig variables
#####

def kig_double(val):
  tp=type(val)
  if tp==TI or tp==TF: return Double(val)
  else:                return val

def kig_int(val):
  tp=type(val)
  if tp==TI:           return Int(val)
  else:                return val

def kig_string(val):
  tp=type(val)
  if tp==TS:           return String(val)
  else:                return val

def kig_point(val):
  tp=type(val)
  if tp==TT:
    x, y = val
    return Point(x, y, internal=True)
  else:
    return val

def kig_relpoint(obj, displ):
  x, y = displ
  return RelativePoint(x, y, obj, internal=True)

#####
# base classes
#####

#####
# Class KigDocument
#####

class KigDocument(object):
  """ This class creates the kig document.

    hierarchy:
      KigDocument <- object

    class attributes:

    attributes:
      axes
      grid
      outfilename
      outfile
      callkig
      of
      viewkig
      hierarchy
      internal
      width
      pointstyle
      name
      linestyle
      shown
      color
      
    methods:
      viewappend
      hierarchyappend
      setcallkig
      setof
      str_open
      close
      noaxes
      nogrid
      hideobjects 
      showobjects 
      setwidth 
      setpointstyle 
      setname 
      setlinestyle 
      setshown 
      setcolor 
      setinternal 
  """

  def __init__(self, outfilename, callkig=True, of=False):
#    print "KigDocument.__init__()"
    self.axes = "1"
    self.grid = "1"
    self.outfilename=outfilename
    self.callkig=callkig
    self.of=of
    try:
      self.outfile = open(outfilename, 'w')
    except IOError, value:
#      print >> sys.stderr, outfilename, 'unwritable'
      print >> sys.stderr, value
      sys.exit(2)
#    KigOut._kigdocument=self
    KigDOP._kd=self
    KigView._kd=self
    self.viewkig=[]
    self.hierarchy=[]
# Defaults values  
    self.internal=False
    self.width=DEFWIDTH
    self.pointstyle=PS[0]
    self.name=DEFNAME
    self.linestyle=LS[0]
    self.shown=VISIBLE
    self.color=DEFCOLOR


  def viewappend(self, e):          self.viewkig.append(e)
  def hierarchyappend(self, e):     self.hierarchy.append(e)
  def setcallkig(v):                self.callkig=v
  def setof(v):                     self.of=v
  
  def str_open(self):
    return """<!DOCTYPE KigDocument>
<KigDocument axes="%s" grid="%s" CompatibilityVersion="0.7.0" Version="0.9.1" >
 <CoordinateSystem>Euclidean</CoordinateSystem>
 <Hierarchy>
""" % (self.axes, self.grid)

  def close(self):
    try:
      self.outfile.write(self.str_open())
      self.outfile.writelines(self.hierarchy)
      self.outfile.write(" </Hierarchy>\n <View>\n")
      for f in self.viewkig:
        self.outfile.write(f.str_view())
      self.outfile.write(" </View>\n</KigDocument>\n")
      if self.outfile != sys.stdout:
        self.outfile.close()
    except IOError, value:
      print >> sys.stderr, value
      sys.exit(2)
    try:
      if self.callkig:
        err = os.system('kig --nofork ' + self.outfilename)
    except Exception, value:
      print >> sys.stderr, value      
    if not self.of:
      os.system('rm ' + self.outfilename)

  def noaxes(self):            self.axes="0"
  def nogrid(self):            self.grid="0"
  def hideobjects(self):       self.shown=HIDDEN
  def showobjects(self):       self.shown=VISIBLE
  def setwidth(self, w):       self.width=w
  def setpointstyle(self, ps): self.pointstyle=ps
  def setname(self, n):        self.name=n
  def setlinestyle(self, ls):  self.linestyle=ls
  def setshown(self, s):       self.shown=s
  def setcolor(self, c):       self.color=c
  def setinternal(self, v):    self.internal=v

#####
# Class KigDOP
#####

#class KigDOP(KigOut):
class KigDOP(object):
  """Base class for all object containing an id: Data, Object, Property.

    hierarchy:
      kigDOP <- object

    class attributes:
      id-counter

    attributes:
      id
      type

    methods:
      getid
      str_hierarchy
  """
  _kd=None
  _id_counter=0

  def __init__(self, type):
    KigDOP._id_counter+=1
    self.id=KigDOP._id_counter
    self._type=type
#    self.getkigdocument().hierarchyappend(self.str_hierarchy())
    KigDOP._kd.hierarchyappend(self.str_hierarchy())

  def getid(self):          return str(self.id)
  def str_hierarchy(self):  pass

#####
# Class KigView
#####

#class KigView(KigOut):
class KigView(object):
  """ Class containing visualization data

    hierarchy:
      KigView <- object

    class attributes:
      _kd
      
    attributes:
      shown
      width
      style
      color
      name
      pointstyle

    methods:
      str_view
      show
      hide
  """
  _kd=None
  
  def __init__(self, object, shown, name, width, pointstyle, linestyle, color):
    self.object=object
    self.shown      = parameter(shown, KigView._kd.shown)
    self.width      = parameter(width, KigView._kd.width)
    self.pointstyle = parameter(pointstyle, KigView._kd.pointstyle)
    self.linestyle  = parameter(linestyle, KigView._kd.linestyle)
    self.color      = parameter(color, KigView._kd.color)
    self.name       = parameter(name, KigView._kd.name)
    KigView._kd.viewappend(self)

  def str_view(self):
    """Creates the string written in <View>.

    Example:
  <Draw width="-1" point-style="Round" namecalcer="none"
style="SolidLine" shown=None color="#0000ff" object="3" />
"""

    return '  <Draw width="%s" point-style="%s" namecalcer="%s"\
 style="%s" shown="%s" color="%s" object="%s" />\n' %\
           (self.width, self.pointstyle, self.name,
            self.linestyle, self.shown, self.color, self.object.getid())

#####
# Class Data
#####

class Data(KigDOP):
  """ Base class for all Data element

    hierarchy:
      Data <- KigDOP <- object

    attributes:
      val

    methods:
      str_hierarchy
"""
  def __init__(self, type, val):
    self.val=val
    KigDOP.__init__(self, type)

  def str_hierarchy(self):
    """Creates the <Data> string.

    Example:
  <Data type="double" id="170" >0.1</Data>
"""
    return '  <Data type="%s" id="%s" >%s</Data>\n' % \
          (self._type, self.getid(), self.val)

#####
# Class PropObj
#####

class PropObj(KigDOP):
  """ Base class for all visible object

    hierarchy:
      PropObj <- KigDOP <- object

    class attributes:

    attributes:
      prop
      objvec
      view

    methods:
      str_hierarchy
      showname(self, n)
      show(self)
      hide(self)
      setwidth(self, width)
      setcolor(self, color)
      setlinestyle(self, linestyle)
      setpointstyle(self, pointstyle)
      setname(self, n)
      setshown(self, s)
      getwidth(self)
      getcolor(self)
      getlinestyle(self)
      getpointstyle(self)
  """
  
  def __init__(self, prop, type, objvec, shown, name, internal,
               width, pointstyle, linestyle, color):
    self.prop=prop
    self.objvec=objvec
    self.n_lb=None
    KigDOP.__init__(self, type)
    internal=parameter(internal, KigDOP._kd.internal)
    if internal:
      self.view = None
    else:
# Here we assume that if an object is named, the name should also be shown.
      if name: n_id=self.showname(name, shown, width, pointstyle, linestyle,
                                  color)
      else:    n_id=None
      self.view = KigView(self, shown, n_id, width, pointstyle, linestyle,
                          color)

  def str_hierarchy(self):
    """Creates the <Data> string.

    Example:
  <Property which="mid-point" id="170" >
   <Parent id="..." />
  </Property>

    or:
  <Object type="ConstrainedPoint" id="14" >
   <Parent id="13" />
   <Parent id="10" />
  </Object>
"""
    retstring = '  <%s="%s" id="%s" >' %\
                ((self.prop and PROPERTY_INI or OBJECT_INI),
                 self._type, self.getid())
    for p in self.objvec:
      retstring = retstring + '\n   <Parent id="%s" />' % p.getid()
    retstring = retstring + '\n  </%s>\n' % (self.prop and PROPERTY_END or
                                                         OBJECT_END)
    return retstring

  def showname(self, name, shown, width, pointstyle, linestyle, color):
    n=String(name)
    self.n_lb=Label(self, (0, 0), n, 0, shown, None, False,
                    width, pointstyle, linestyle, color)
    return n.getid()
    
  def show(self):
    if self.view:                  self.view.shown=None
  def hide(self):
    if self.view:                  self.view.shown=KIGFALSE
  def setwidth(self, width):       self.view.width=width
  def setcolor(self, color):       self.view.color=color
  def setlinestyle(self, linestyle):
    if linestyle in LS:            self.view.linestyle=linestyle
  def setpointstyle(self, pointstyle):
    if pointstyle in PS:           self.view.pointstyle=pointstyle
  def type(self):                  return Type(self)
  def setname(self, n):
    v=self.view
    v.name=self.showname(n, v.shown, v.width, v.pointstyle, v.linestyle,
                         v.color)
  def setshown(self, s):           self.view.shown=s

#####
# Class Property
#####

class Property(PropObj):
  """ Base class for all Property elements

    hierarchy:
      Property <- PropObj <- KigDOP <- object
  """
  def __init__(self, type, parent, shown, name, internal,
               width, pointstyle, linestyle, color):
    PropObj.__init__(self, True, type, (parent,), shown, name, internal,
               width, pointstyle, linestyle, color)
#    print shown

#####
# Class Object
#####

class Object(PropObj):
  """ Base class for all Object elements

    hierarchy:
      Object <- PropObj <- KigDOP <- object
  """

  def __init__(self, type, objvec, shown, name, internal,
               width, pointstyle, linestyle, color):
    PropObj.__init__(self, False, type, objvec, shown, name, internal,
               width, pointstyle, linestyle, color)
 
#####
# Data
#####

data=(\
("Int",    "int",    "val"),
("Double", "double", "val"),
("String", "string", "convstr(val)"),
)

def convstr(s):
  for o, n in DICT:
    s=s.replace(o, n)
  return s

def databuild(nomeclasse, nomekig, v="val"):
  """Create string with a Data class definition."""
  return """class %s(Data):

  def __init__(self, val):
    Data.__init__(self, "%s", %s)
""" % (nomeclasse, nomekig, v)

for d in data:
  p1, p2, p3 = d
  exec databuild(p1, p2, p3)

#####
# Objects
#####
"""To be added:
("ConvexHall", "ConvexHall", "polygon,", "(polygon,),"),
("EllipseByFocusFocusPoint", "EllipseBFFP", "p1, p2, p3,", "(p1, p2, p3,),"),
("HyperbolaByFocusFocusPoint", "HyperbolaBFFP", "p1, p2, p3,", "(p1, p2, p3,),"),
(ConicsBy5Points", "ConicB5P", "p1, p2, p3, p4, p5,", "(p1, p2, p3, p4, p5),"),
("ParabolaBy3Points", "ParabolaBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
("CocCurve", "CocCurve", "line, point,", "(line, point,),"),
"""
objects=(\
###### Points class
("Point",           "FixedPoint", "x, y,", "(kig_double(x), kig_double(y)),"),
("ConstrainedPoint", "ConstrainedPoint",
                    "t, curve,", "(kig_double(t), curve),"),
("RelativePoint",   "RelativePoint",
                    "x, y, p,", "(kig_double(x), kig_double(y), p),"),
###### segments, rays, lines
("Line",            "LineAB", "p1, p2,", "(p1, p2),"),
("Segment",         "SegmentAB", "p1, p2,", "(p1, p2),"),
("Ray",             "RayAB", "p1, p2,", "(p1, p2),"),
("Orthogonal",      "LinePerpend", "line, point,", "(line, point,),"),
("Parallel",        "LineParallel", "line, point,", "(line, point,),"),
###### Circles, arcs, ...
("Circle",          "CircleBCP", "center, point,", "(center, point,),"),
("CircleByCenterRadius", "CircleBPR", "center, radius,", "(center, radius,),"),
("CircleBy3Points",  "CircleBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
("ArcBy3Points",    "ArcBTP", "p1, p2, p3,", "(p1, p2, p3,),"),
("ArcByCenterPointAngle", "ArcBCPA",
                    "center, point, angle,", "(center, point, angle),"),
###### Conics...
("ParabolaByDirectrixFocus", "ParabolaBDP", "line, point,", "(line, point,),"),
("VerticalCubic", "VerticalCubicB4P", "p1, p2, p3, p4,", "(p1, p2, p3, p4),"),
("ConicArc", "ConicArcBTPC", "p1, p2, p3, center,", "(p1, p2, p3, center),"),
#####
# intersections.  The only standard object is the intersection
# of two lines, which always gives one single point
#####
("LineLineIntersection", "LineLineIntersection", "l1, l2,", "(l1, l2),"),
#####
# Class CircleCircleIntersection and ConicLineIntersection
# the value of the "which" integer (1 or -1) indicates which of the two
# intersections we want to get.
#####
("CircleCircleIntersection", "CircleCircleIntersection",
                    "c1, c2, witch,", "(c1, c2, Int(witch),),"),
("ConicLineIntersection", "ConicLineIntersection",
                    "conic, line, witch,", "(conic, line, Int(witch),),"),
###### Class Triangle
("Triangle",        "TriangleB3P", "p1, p2, p3,", "(p1, p2, p3),"),
###### Class Polygon   (the only argument is a points vect)
("Polygon",         "PolygonBNP", "pvec,", "pvec,"),
###### Class PolygonBCV
# Regular polygon given the center and a vertex; the third parameter
# is an integer containing the number of sides.
("PolygonBCV",      "PoligonBCV",
                    "center, vertex, n,", "(center, vertex, Int(n)),"),
##### Class PolygonVertex    (polygon, integer >= 0)
("PolygonVertex",   "PolygonVertex",
                    "polygon, i,", "(polygon, Int(i)),"),
##### Class PolygonSide    (polygon, integer >= 0)
("PolygonSide",     "PolygonSide",
                    "polygon, i,", "(polygon, Int(i)),"),
###### vector, angle,...
("Vector",          "Vector", "p1, p2,", "(p1, p2),"),
("Angle",           "Angle", "p1, v, p2,", "(p1, v, p2),"),
###### Transformations
("Translate",       "Translation", "obj, vector,", "(obj, vector),"),
("CentralSymmetry", "PointReflection", "obj, center,", "(obj, center),"),
("AxialSymmetry",   "LineReflection", "obj, center,", "(obj, center),"),
("Rotate",          "Rotation",
                    "obj, center, angle,", "(obj, center, angle),"),
("Scale",           "ScalingOverCenter",
                    "obj, center, segment,", "(obj, center, segment),"),
("Scale2",          "ScalingOverCenter2",
                    "obj, center, s1, s2,", "(obj, center, s1, s2),"),
("InvertPoint",     "InvertPoint",
                    "point, circle,", "(point, circle),"),
("CircularInversion", "CircularInversion",
                    "objecttoinvert, circle,", "(objecttoinvert, circle),"),
("InvertLine",      "InvertLine",
                    "line, circle,", "(line, circle),"),
("InvertCircle",    "InvertCircle",
                    "circletoinvert, circle,", "(circletoinvert, circle),"),
("InvertArc",       "InvertArc",
                    "arctoinvert, circle,", "(arctoinvert, circle),"),
("InvertSegment",   "InvertSegment",
                    "segment, circle,", "(segment, circle),"),
###### Text, Label, ...
("Text",            "Label",
                    "point, string, boxed=0,",
                    "(Int(boxed), kig_point(point), kig_string(string)),"),
("Label",           "Label",
                    "obj, displ, string, boxed=0,",
                    "(Int(boxed),kig_relpoint(obj, displ),kig_string(string)),"),
("VarText",         "Label",
                    "point, string, vars, boxed=0,",
                    "(Int(boxed), kig_point(point), \
                    kig_string(string))+tuple(vars),"),
("VarLabel",        "Label",
                    "obj, displ, string, vars, boxed=0,",
                    "(Int(boxed), kig_relpoint(obj, displ), \
                    kig_string(string))+tuple(vars),"),
###### Python scripting... we need some work here...
("PythonScript",    "PythonExecuteType",
                    "script, argvec,",
                    '(Object("PythonCompileType", (kig_string(script),), shown,\
                             name, internal, width, pointstyle, linestyle,\
                             color),)+tuple(argvec),'),
)

def objectbuild(nameclass, namekig, params, objparams):
  """Create string with a Object class definition."""
  return """class %s(Object):

  def __init__(self, %s shown=None, name=None, internal=None,
               width=None, pointstyle=None, linestyle=None, color=None):
    Object.__init__(self, "%s", %s shown, name, internal,
                    width, pointstyle, linestyle, color)
""" % (nameclass, params, namekig, objparams)

for o in objects:
  p1, p2, p3, p4 = o
  exec objectbuild(p1, p2, p3, p4)

#####
# Propertys
#####

property=(\
("Type",            "base-object-type", "o,", "o,"),
("Coordinate",      "coordinate", "point,", "point,"),
("XCoord",          "coordinate-x", "point,", "point,"),
("YCoord",          "coordinate-y", "point,", "point,"),
("MidPoints",       "mid-point", "a, b,", "Segment(a, b, internal=True),"),
("MidPoint",        "mid-point", "segment,", "segment,"),
("EndPointA",       "end-point-A", "segment,", "segment,"),
("EndPointB",       "end-point-B", "segment,", "segment,"),
("Length",          "length", "segment,", "segment,"),
("Equation",        "equation", "segment,", "segment,"),
("Slope",           "slope", "segment,", "segment,"),
("NumOfSides",      "polygon-number-of-sides", "poly,", "poly,"),
("Perimeter",       "polygon-perimeter", "poly,", "poly,"),
("Surface",         "polygon-surface", "poly,", "poly,"),
("CenterOfMass",    "polygon-center-of-mass", "poly,", "poly,"),
("WindingNumber",   "polygon-winding-number", "poly,", "poly,"),
("Radius",          "radius", "circle,", "circle,"),
("Center",          "center", "circle,", "circle,"),
("Bisector",        "angle-bisector", "angle,", "angle,"),
("Support",         "support", "object,", "object,"),
)

def propertybuild(nameclass, namekig, params, objparams):
  """Create string with a Property class definition."""
  return """class %s(Property):

  def __init__(self, %s shown=None, name=None, internal=False,
               width=None, pointstyle=None, linestyle=None, color=None):
    Property.__init__(self, "%s", %s shown, name, internal,
                    width, pointstyle, linestyle, color)
""" % (nameclass, params, namekig, objparams)

for p in property:
  p1, p2, p3, p4 = p
  exec propertybuild(p1, p2, p3, p4)

#####
# Start of properties definitions as Object's metod
#####
# fixme!
points  =(Point, ConstrainedPoint, RelativePoint, PolygonVertex)
lines=(Segment, Ray, Vector, InvertLine)
segments=(Segment, Vector, PolygonSide, InvertSegment)
circles =(Circle, CircleBy3Points, CircularInversion, ArcBy3Points,
          ArcByCenterPointAngle, InvertCircle)
polygons=(Polygon, PolygonBCV, Triangle)
angles  =(Angle,)
supp    = circles+lines

methods=(\
("coordinate", "coordinate", points),
("coordinate-x", "xcoord", points),
("coordinate-y", "ycoord", points),
("mid-point", "midpoint", segments),
("end-point-A", "endpointA", segments),
("end-point-B", "endpointB", segments),
("length", "length", segments),
("equation", "equation", lines),
("slope", "slope", lines),
("polygon-number-of-sides", "numofsides", polygons),
("polygon-perimeter", "perimeter", polygons),
("polygon-surface", "surface", polygons),
("polygon-center-of-mass", "centerofmass", polygons),
("polygon-winding-number", "windingnumber", polygons),
("center", "center", polygons),
("center", "center", circles),
("angle-bisector", "bisector", angles),
("support", "support",  supp),
)

def methodsbuild(namekig):
  """Create string with a method class definition."""
  return """def method(self,shown=None, name=None, internal=False,
               width=None, pointstyle=None, linestyle=None, color=None):
    return Property("%s", self, shown, name, internal,
                    width, pointstyle, linestyle, color)
""" % (namekig, )

for p in methods:
  p1, p2, cl = p
  exec methodsbuild(p1)
  for c in cl:
    setattr(c, p2, method)

#####
# Usage
#####

def usage(codexit):
  print >> sys.stderr, """
usage: pykig.py [options...] file ...

Options:
    -h, --help          Show this text.
    -o <kig_file>
    --output <kig_file> output <kig_file> no call Kig
    -v, --version       output version
    -n, --nokig         no call Kig

examples:
    $ pykig.py my_file.kpy
    $ pykig.py -o output_file.kig my_file.kpy
    $ ...
"""
  sys.exit(codexit)

#####
# Main body
#####

import sys, traceback, os
#from math import *    # for user's programs
import math            # for user's programs
import getopt
import atexit

def prog():
  try:
    _opts, _args = getopt.getopt(sys.argv[1:], "hvno:",\
                                 ["help", "version", "nokig", "output="])
  except getopt.GetoptError:
    print "GetoptError"
    usage(2)
  _callKig=True
  _of=False
  for _opt, _arg in _opts:
    if _opt in ("-h", "--help"):
      usage(0)
    if _opt in ("-v", "--version"):
      print "version:", version
      sys.exit(0)
    if _opt in ("-n", "--nokig"):
      _callKig=False
    elif _opt in ("-o", "--output"):
      _outfilename=_arg
      _of=True
      _callKig=False   # if the output filename is provided, don't call Kig
  if len(_args)==0:
    _infilename=raw_input("Input filename: ")
    if not _infilename:
      print "No Input filename"
      usage(2)
  elif len(_args)==1:
    _infilename=_args[0]
  else:
    print "No infilename"
    usage(2)
  try:
    _infile = open(_infilename, 'r')
  except:
    print >> sys.stderr, _infilename, 'unreadable'
    sys.exit(2)
  if _of:
    if _outfilename=="-":
      _n, _e = os.path.splitext(_infilename)
      _outfilename=_n+'.kig'
  else:
    _outfilename="/tmp/pykig" + str(os.getpid()) + ".kig"
  global kigdocument
  kigdocument=KigDocument(_outfilename, _callKig, _of)
  kd=kigdocument
  try:
    execfile(_infilename, globals())
  except:
    print >> sys.stderr, 'syntax error in', _infilename
    _info = sys.exc_info()    # print the traceback
    traceback.print_exc()
    sys.exit(3)
  kigdocument.close()

  if _infile != sys.stdin:
    _infile.close()

def lib():
  _outfilename="/tmp/pykig" + str(os.getpid()) + ".kig"
  global kigdocument
  kigdocument=KigDocument(_outfilename)
  kd=kigdocument
  atexit.register(kigdocument.close)

if __name__ == "__main__":
  prog()
else:
  lib()
