#
# This file is part of GNU Enterprise.
#
# GNU Enterprise 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 2, or (at your option) any later version.
#
# GNU Enterprise 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 program; see the file COPYING. If not,
# write to the Free Software Foundation, Inc., 59 Temple Place
# - Suite 330, Boston, MA 02111-1307, USA.
#
# Copyright 2002-2007 Free Software Foundation
#
# FILE:
# sio.py
#
# DESCRIPTION:
#
# NOTES:
#



#
# sio.py
#
# An interface to curses
#

from constants import *
import curses

#C_SCREEN = 2
#C_TITLEBAR = 3
#C_MENUBAR = 4
#C_MENUBAR_FOCUS = 5
#C_LABEL = 6
#C_DIALOG = 7
#C_DIALOG_TITLE = 8
#C_TEXTBOX_FOCUS = 9
#C_TEXTBOX = 10
#C_BUTTON = 11
#C_BUTTON_FOCUS = 12
#C_SCROLL_BUTTON = 13
#C_SCROLL_BUTTON_FOCUS = 14
#C_SCROLL_BACKGROUND = 15
#C_SCROLL_SLIDER = 16
#C_SCROLL_SLIDER_FOCUS = 17
#C_STATUSBAR = 10
#C_STATUSBAR_FIELD = 10  # 7


def sio(*args, **parms):
  global _sio
  if not _sio:
    _sio = _Sio(*args, **parms)
  return _sio

_sio = None

class _Sio:
  """
  This class basically acts as an interface to curses.

  """
  def __init__(self):

    self.Started = 0

    self.MAXCOL = -1
    self.MAXROW = -1

    self.s = None     # s is a full screen curses window
    self.stdscr = None  # holds instance of full console screen

    self.TokNextField = 9
    self.TokActivate = 10

    # get curses keyevents into local tokens
    # TODO: what about ascii key maps?  ascii.BS?  Maybe should
    # modify these to handle tuples.
    self.TokBackspace = curses.KEY_BACKSPACE
    self.TokUpArrow = curses.KEY_UP
    self.TokDownArrow = curses.KEY_DOWN
    self.TokRightArrow = curses.KEY_RIGHT
    self.TokLeftArrow = curses.KEY_LEFT
    self.TokHomeKey = curses.KEY_HOME
    self.TokEndKey = curses.KEY_END


  def BeginScreenAccess(self):
    """Initialize the screen and setup for action."""
    assert gDebug(0,'initializing curses screen')
    #if self.s <> None:
    #  return
    assert gDebug(0,'initializing curses screen 1')
    self.stdscr = curses.initscr()
    self._NegotiateScreenSize()
    assert gDebug(0,'initializing curses screen 2')
    self.s = curses.newwin(self.MAXROW+1, self.MAXCOL+1, 0, 0)
    curses.noecho()
    assert gDebug(0,'initializing curses screen 3')
    #curses.nonl()  # disallows usage of <CR> as a selector.
    curses.cbreak()
    self.s.keypad(1)
    assert gDebug(0,'initializing curses screen 4')
    # make the cursor very visible
    #curses.curs_set(2) # throws an ERR, removing.

    global ti_chars
    ti_chars = {
      tiHLINE : curses.ACS_HLINE,
      tiVLINE : curses.ACS_VLINE,
      tiBOX : curses.ACS_BOARD,
      tiLLC : curses.ACS_LLCORNER,
      tiLRC : curses.ACS_LRCORNER,
      tiDAW : curses.ACS_DARROW,
      tiULC : curses.ACS_ULCORNER,
      tiURC : curses.ACS_URCORNER,
      tiUTEE : curses.ACS_TTEE,
      tiLTEE : curses.ACS_LTEE,
      tiRTEE : curses.ACS_RTEE,
      tiBULL : curses.ACS_PLUS}
    assert gDebug(0,'initializing curses screen 5')

    # TODO: should really only do this if configuration
    # TODO: says yes, or on some other test.
    curses.start_color()

    import ColorScheme

    if curses.has_colors():
      assert gDebug(1,"Initializing StandardWhiteOnBlue colors")
      self.colors = ColorScheme.StandardWhiteOnBlue()

#        curses.init_pair(C_SCREEN, curses.COLOR_WHITE,curses.COLOR_BLUE)
#        curses.init_pair(C_TITLEBAR, curses.COLOR_WHITE,curses.COLOR_BLUE)
#        curses.init_pair(C_MENUBAR, curses.COLOR_YELLOW,curses.COLOR_BLUE)
#        curses.init_pair(C_MENUBAR_FOCUS, curses.COLOR_BLUE,curses.COLOR_WHITE)
#        curses.init_pair(C_LABEL, curses.COLOR_BLACK,curses.COLOR_WHITE)
#        curses.init_pair(C_DIALOG, curses.COLOR_BLACK,curses.COLOR_WHITE)
#        curses.init_pair(C_DIALOG_TITLE, curses.COLOR_YELLOW,curses.COLOR_WHITE)
#        curses.init_pair(C_TEXTBOX_FOCUS, curses.COLOR_BLACK,curses.COLOR_CYAN)
##        curses.init_pair(C_TEXTBOX, curses.COLOR_WHITE,curses.COLOR_BLUE)
#        curses.init_pair(C_TEXTBOX, curses.COLOR_BLUE,curses.COLOR_WHITE)
#        curses.init_pair(C_BUTTON, curses.COLOR_BLUE,curses.COLOR_WHITE)
##        curses.init_pair(C_BUTTON_FOCUS, curses.COLOR_WHITE,curses.COLOR_CYAN)
#        curses.init_pair(C_SCROLL_BUTTON, curses.COLOR_BLACK,curses.COLOR_WHITE)
#        curses.init_pair(C_SCROLL_BUTTON_FOCUS, curses.COLOR_CYAN,curses.COLOR_WHITE)
#        curses.init_pair(C_SCROLL_BACKGROUND, curses.COLOR_BLUE,curses.COLOR_GRAY)
#        curses.init_pair(C_SCROLL_SLIDER, curses.COLOR_WHITE,curses.COLOR_BLUE)
#        curses.init_pair(C_SCROLL_SLIDER_FOCUS, 0, curses.COLOR_CYAN)
##        curses.init_pair(C_STATUSBAR, curses.COLOR_BLACK, curses.COLOR_WHITE)
##        curses.init_pair(C_STATUSBAR_FIELD, curses.COLOR_BLUE, curses.COLOR_WHITE)
    else:
      assert gDebug(1,"Initializing Monochrome colors")
      self.colors = ColorScheme.Monochrome()



    events = curses.mousemask(curses.BUTTON1_CLICKED)

#    if events == 0:
#      self.PrintAt(self.MAXROW, self.MAXCOL-8, 'no mouse.')

    self.AutoRefresh = 1
    self.Started = 1
    self.PrintMods = 0

    return(self.s)


  def EndScreenAccess(self):
    # S is nothing, no need to end curses stuff
    if self.s == None:
      return
    self.Cls()
    curses.nocbreak()
    self.s.keypad(0)
    curses.echo()
    curses.endwin()


  def CaptureScreen(self, r1, c1, r2, c2):
    """
    Return a rectangle within the screen specified from corner 1 at
    (r1,c1) to corner 2 at (r2,c2).
    """

    scrnbuff = {}
    for rows in range(r1, r2):
      for cols in range(c1, c2):
        scrnbuff[str(rows)+"X"+str(cols)]=self.GetCharAt(rows,cols)
    return scrnbuff


  def RestoreScreen(self, r1, c1, r2, c2, scrnbuff):
    """
    Redraw screen within any rectangle from buffer.  Does nothing if
    buffer passed is {}.
    """
    if scrnbuff == {}:
      return

    self.AutoRefresh = 0
    self.LoLight()

    for rows in range(r1, r2):
      for cols in range(c1, c2):
        self.PutAt(rows,cols, scrnbuff[str(rows)+"X"+str(cols)])

    self.AutoRefresh = 1
    self.Refresh()


  def _NegotiateScreenSize(self):
    """ Private:
    Set self.MAXROW and self.MAXCOL less one pixel from
    stdscr.getmaxyx() which returns tuple (y,x) of height and width of
    the window.  """
    (lmaxY, lmaxX) = self.stdscr.getmaxyx()
    self.MAXROW = lmaxY - 1
    self.MAXCOL = lmaxX - 1



#
# suggest depricate and remove this def.  Is it used for
# forms compatibility?
#
  def GetScreenInstance(self):
    """
    """
    return self.s


  def SetScreenInstance(self, s):
    """
    """
    self.s = s


  def GetCharAt(self, Row, Col):
    """
    """
    return self.s.inch(Row, Col)


  def GetChar(self):
    """
    """
    return self.s.getch()


  def GetStr(self,Y,X,N):
    """
    FIXME:
    Retrieve a string N long from (X,Y) traveling along
    """
    result = []
    for i in range(0,N):
      result.append(self.s.inch(Y+i,X))
    return result


  def GotoYX(self, Row, Col):
    self.s.move( Row, Col)
    if self.AutoRefresh :
      self.s.refresh()

  def GetYX(self):
    return self.s.getyx()

  def Print(self, String, Mods = 0):
#    PrevMod = self.PrintMods
#    if Mods != None:
#      PrevMod |= Mods
    PrevMod = Mods

    refreshState = self.AutoRefresh
    self.AutoRefresh = 0

    for i in range(0,len(String)):
      if ti_chars.has_key(ord(String[i])):
        actch = ti_chars[ord(String[i])]
        self.s.addch(actch, PrevMod)
      else:
        self.s.addstr(str(String[i]), PrevMod)

    self.AutoRefresh = refreshState

    if self.AutoRefresh :
      self.s.refresh()


  def PutAt(self,Y,X,Char, Mods = None):
    """
    """
    PrevMod = self.PrintMods
    if Mods != None:
      PrevMod |= Mods
    try:
      self.s.addch(Y,X,Char,PrevMod)
    except curses.error:
      pass


  def HiLight(self):
    """
    """
    return


    if curses.has_colors():
      # TODO: should this be curses.color_pair(colorHi)?
      #self.PrintMods = curses.color_pair(colorHi)
      self.PrintMods = curses.A_BOLD
    else:
      self.PrintMods = curses.A_NORMAL


  def LoLight(self):
    """
    """
    return


    if curses.has_colors():
      self.PrintMods = curses.color_pair(colorLow)
    else:
      self.PrintMods = curses.A_DIM


  def SetColor(self, ll, hl=None):
    """
    """
    return


##    if type(ll) == type( (0,) ):
##      ll, hl = ll

##    self.COLOR = (ll,hl)
    self.COLOR = ll
    try:
      if curses.has_colors():
        self.PrintMods = curses.color_pair(ll)
    except AttributeError:
      pass

  def GetColor(self):
    return 0
    #return self.COLOR


  def PrintAt(self, Row, Col, String, Mods = 0):
    """
    """
    self.GotoYX(Row, Col)
    self.Print(String,Mods)


  def Cls(self):
    """
    """
    self.AutoRefresh = 0
    for row in range(0, self.MAXROW+1):
      self.PrintAt(row, 0, " " * self.MAXCOL, self.colors.C_BACKGROUND)
    self.AutoRefresh = 1


  def Refresh(self):
    """
    """
    self.s.refresh()
