#!/usr/bin/env python/

import sys
import string
import time
import struct
import curses
import curses.ascii
import curses.wrapper

INPUT_TIMEOUT= 10
STORED_SCREENS= 2

class MyWin:
    def __init__( self, rows, cols, y, x ):
        self.y= y
        self.x= x
        self.rows= rows
        self.cols= cols
        self.w= curses.newwin( rows, cols, y, x )
        #self.w.bkgdset( 0, curses.COLOR_YELLOW )
        self.w.scrollok(1)

    def resize( self, sizeY, sizeX, y, x ):
        self.w= curses.newwin( sizeY, sizeX, y, x )
        self.x= x
        self.y= y
        self.rows= sizeY
        self.cols= sizeX
        self.w.scrollok(1)
    
    def addch( self, char ):
        self.w.addch( char )
    
    def addstr( self, text, attr= None ):
        if attr:
            self.w.addstr( text, attr )
        else:    
            self.w.addstr( text )
    
    def erase( self ):
        self.w.erase() 

    def refresh( self ):
        self.w.refresh()

    
class MyScrollWin(MyWin):
    def __init__( self, rows, cols, y, x ):
        MyWin.__init__( self, rows, cols, y, x )
        self.pRows= rows * STORED_SCREENS
        self.p= curses.newpad( self.pRows, cols )
        self.p.scrollok(1)
        self.scroll= 0
        self.text= []
    
    def addch( self, char ):
        self.p.addch( char )
    
    def addstr( self, text, attr= None ):
        self.text.append( (text, attr) )
        #print >>sys.stderr, 'paso'

        try:
            if attr:
                self.p.addstr( text, attr )
            else:    
                self.p.addstr( text )
        except curses.error, e:
            #print >>sys.stderr, 'UOP', e
            pass
            

        (padY, padX)= self.p.getyx()
        (scrY, scrX)= self.p.getmaxyx()

        #print >>sys.stderr, 'pady= ', padY
        #print >>sys.stderr, 'scrY= ', scrY

        if padY >= (scrY - 1):
            self.pRows*= 2
            self.p= curses.newpad( self.pRows, scrX )
            self.redraw()

    def dump( self, file ):
        for elem in self.text:
            file.write( elem[0] )
        file.close()    

    def resize( self, sizeY, sizeX, y, x ):
        #print >>sys.stderr, 'newpad: sizeY= %d, sizeX= %d' % ( sizeY * STORED_SCREENS, sizeX )
        #print >>sys.stderr, 'resizePad: sizeY= %d, sizeX= %d' % ( sizeY, sizeX )
        
        self.p= curses.newpad( self.pRows, sizeX )
        self.x= x
        self.y= y
        self.rows= sizeY
        self.cols= sizeX


        #print >>sys.stderr, 'text=', self.text
        self.redraw()


    def refresh( self ):
        (y, x)= self.p.getyx()
        firstRow= y - (self.rows - 1)
        if (firstRow + self.scroll) < 0:
            firstRow= 0
        #print >>sys.stderr, str(self), firstRow + self.scroll, self.x, self.y, self.x                          , self.y+self.rows-1, self.cols-1

        #(scrY, scrX)= curses.getmaxyx()
        #rows= self.rows
        #cols= self.cols
        #if scrY < rows:
            #rows= scrY
        #if scrX < cols:
            #cols= scrX
        
        #print >>sys.stderr, 'prefresh: pminrow= %d, pmincol= %d, sminrow= %d, smincol= %d, smaxrow= %d, smaxcol= %d' % \
            #(firstRow + self.scroll, 0, self.y, 0  \
            #, self.y+self.rows-1, self.cols-1)
        #print >>sys.stderr, 'self.y= %d' % (self.y)
        #print >>sys.stderr, 'self.rows= %d' % (self.rows)
        sizeY= self.y+self.rows-1
        (padY, padX)= self.p.getyx()
        #print >>sys.stderr, 'sizeY= %d, padY= %d' % (sizeY, padY)
            
        try:        
            self.p.refresh(firstRow + self.scroll, 0, self.y, 0
                , self.y+self.rows-1, self.cols-1)
        except curses.error:
            pass
        #self.p.refresh(firstRow + self.scroll, self.x, self.y, self.x
            #, self.y+self.rows-1, self.cols-1)

    def redraw( self ):
        self.p.erase()
        for elem in self.text:
            #print >>sys.stderr, 'elem=', elem
            if elem[1] == None:
                self.p.addstr( elem[0] )
            else:
                self.p.addstr( elem[0], elem[1] )

    def attrset( self, color ):
        self.p.attrset( color )

    def toTop( self ):
        (y, x)= self.p.getyx()
        self.scroll= -(y - self.rows +1) 

    def toBottom( self ):
        self.scroll= 0
    
    def line( self ):
        (y, x)= self.p.getyx()
        (maxY, maxX)= self.p.getmaxyx()
        #print >>sys.stderr, '%d %d - ' % (x, y)
        #print >>sys.stderr, '%d %d' % (maxX, maxY)
        self.p.hline( y, x, curses.ACS_HLINE, maxX - x )
   
    def scrollUp( self, lines= 1 ):
        (y, x)= self.p.getyx()
        firstRow= y - self.rows
        if (firstRow + self.scroll - lines ) >= 0:
            self.scroll-= lines
        else:    
            self.scroll= -(y - self.rows +1) 
        self.refresh()

    def getWin( self ):
        return self.w

    def erase( self ):
        self.text= []
        self.p.erase() 
        #self.refresh()

    def scrollDown( self, lines= 1 ):
        (y, x)= self.p.getyx()
        if (self.scroll + lines) < 0:
            self.scroll+= lines
        else:    
            self.scroll= 0 
        self.refresh()
        
class MyInputWin(MyScrollWin):
    def __init__( self, rows, cols, y, x ):
        MyScrollWin.__init__( self, rows, cols, y, x )
        self.p.timeout( INPUT_TIMEOUT )
        self.p.keypad(1)
        self.attr= None
        #print >>sys.stderr, str(self), self.rows, self.cols, self.y, self.x
        self.hidden= 0
    
    def setAttr( self, attr ):
        self.attr= attr
    
    def resize( self, sizeY, sizeX, y, x ):
        MyScrollWin.resize( self, sizeY, sizeX, y, x )
        self.p.timeout( INPUT_TIMEOUT )
        self.p.keypad(1)
    
    def getLine( self, handleFunc= None, idleFunc= None, hidden= 0 ):
        #curses.noecho()
        self.p.immedok(0)
        #l= open('/tmp/jeje', 'w')
        self.buff= ''
        self.pos= 0
        self.hidden= hidden
        while 1:
            c= self.p.getch()
            #l.write( str(c) )
    
            #print >>sys.stderr, 'leido= %s\n' % str(c) 
            if c == curses.ascii.NL:
                break
            elif c != curses.ERR:
                #print >>sys.stderr, 'en el elif'
                if not handleFunc( c ):
                    #print >>sys.stderr, 'en if'
                    if self.pos < len(self.buff):
                        self.buff= self.buff[:self.pos] + chr(c) \
                            + self.buff[self.pos:]
                        self.erase()    
                        #print >>sys.stderr,  'lala= %s' % self.buff 
                        if not self.hidden:
                            #print >>sys.stderr, 'en if2'
                            if self.attr:
                                self.p.addstr( self.buff, self.attr )
                            else:
                                self.p.addstr( self.buff )
                            self.cursPos(self.pos+1)
                            self.refresh()
                    else:    
                        self.buff+= chr(c)
                        if not self.hidden:
                            #print >>sys.stderr, 'self.attr' 
                            if self.attr:
                                self.p.addch( c, self.attr )
                            else:    
                                self.p.addch( c )
                            #print >>sys.stderr, 'getLine=', self.p.getyx()
                            self.refresh()

                    self.pos += 1
            else:        
                if idleFunc != None:
                    idleFunc()
                else:
                    curses.napms( 1 )

        
        self.hidden= 0
        return self.buff

    #def refresh( self ):
        #(y, x)= self.p.getyx()
        #firstRow= y - self.rows
        #if (firstRow + self.scroll) < 0:
            #firstRow= 0
        #print >>sys.stderr, firstRow + self.scroll, 0, self.y, self.x, self.y+self.rows-1, self.cols-1
        #self.p.refresh(firstRow + self.scroll, 0, self.y+1, self.x, self.rows-1
            #, self.cols-1)
        #self.p.refresh(0, 0, 23, 0, 24, 79)

    def delChar( self ):
        if self.pos >= 1:
            self.pos-= 1
            self.buff= self.buff[:self.pos] + self.buff[self.pos+1:]
            if not self.hidden:
                self.p.erase()
                if self.attr:
                    self.p.addstr( self.buff, self.attr )
                else:    
                    self.p.addstr( self.buff )
                self.cursPos( self.pos )


    def suprChar( self ):
        self.buff= self.buff[:self.pos] + self.buff[self.pos+1:]
        if not self.hidden:
            self.p.erase()
            if self.attr:
                self.p.addstr( self.buff, self.attr )
            else:    
                self.p.addstr( self.buff )
            self.cursPos( self.pos )
            
    def cursPos( self, pos ):
        y= pos/self.cols
        x= pos%self.cols

        #print >>sys.stderr, 'cursor=', self.p.getyx()
        self.p.move( y, x )

        if y >= self.rows:
            y= self.rows - 1
        #print >>sys.stderr, '/= %d, %%=%d' % (pos/self.cols, pos%self.cols) 
        #print >>sys.stderr, 'move=', y, x
        self.w.move( y, x )

    def cursBegin( self ):
        self.pos= 0
        self.cursPos( self.pos )

    def cursEnd( self ):
        self.pos= len( self.buff )
        self.cursPos( self.pos )

    def cursBack( self ):
        if self.pos >= 1:
            self.pos-= 1
            self.cursPos( self.pos )

    def cursForward( self ):
            if self.pos < len(self.buff):
                self.pos+= 1
                self.cursPos( self.pos )

    def addstr( self, text ):
        self.buff= text
        self.pos= len( text )
        self.p.addstr( text )


class MyWinStack:        
    def __init__( self, rows, cols, y, x ):
        self.y= y
        self.x= x
        self.rows= rows
        self.cols= cols
        #w= MyScrollWin( rows, cols, y, x )
        self.wins= {}

    def resize( self, sizeY, sizeX, y, x ):
        self.y= y
        self.x= x
        self.rows= sizeY
        self.cols= sizeX
        for win in self.wins.values():
            win.resize( sizeY, sizeX, y, x )

    def dump( self, chat, file ):
        self.wins[chat].dump( file )

    def newWin( self, chat ):
        w = MyScrollWin( self.rows, self.cols, self.y, self.x )
        self.wins[chat]= w
  
    # Looks for a window which has a chat with only the user 'user'
    # returns the old chat
    def reuseWindow( self, newChat ):
        if len(newChat.users) != 1:
            return None

        user = newChat.listUsers()[0]
        for chat in self.wins.keys():
            if (user in chat.listUsers()) and len(chat.listUsers())==1:
                self.replaceChat(chat, newChat)
                return chat
        
        return None

    def replaceChat( self, oldChat, newChat ):
        self.wins[newChat]= self.wins[oldChat]
        self.delWin( oldChat )
        #print >>sys.stderr, 'self.wins: ', self.wins
    
    def hasWin( self, chat ):
        return self.wins.has_key( chat )

    def show( self, chat ):
        w= self.wins[chat]
        w.refresh()

    def delWin( self, chat ):
        if self.wins.has_key(chat):
            del( self.wins[chat] )

    def erase( self, chat ):
        self.wins[chat].erase()

    def addstr( self, chat, text, attr= None ):
        if self.wins.has_key( chat ):
            w= self.wins[chat]
            try:
                w.addstr( text, attr )
            except curses.error:    
                self.addstr( None, _('Detected ERROR when displaying: ') + text )

    def scrollUp( self, chat, lines= 1 ):
        w= self.wins[chat]
        w.scrollUp( lines )

    def scrollDown( self, chat, lines= 1 ):
        w= self.wins[chat]
        w.scrollDown( lines )

    def toTop( self, chat ):
        self.wins[chat].toTop()

    def toBottom( self, chat ):
        self.wins[chat].toBottom()
    
    def redraw( self ):
        for w in self.wins.values():
            w.redraw()

    def refresh( self, chat ):
        if self.wins.has_key(chat):
            w= self.wins[chat]
            w.refresh()
        
        
def dummy( c ):
    return 1

def main(a):
    #curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)
    #curses.meta(1)
    v1= MyWin( 22, 80, 0, 0 )
    v2= MyInputWin(2, 80, 22, 0)

    #v1.hline(21, 0, curses.ACS_HLINE, 80)
    
    #p1.refresh(0, 0, 0, 0, 22, 80)
    #p2.refresh(0, 0, 22, 0, 24, 80)
    v1.refresh()
    v2.refresh()

    while 1:
        st= v2.getLine( dummy, hidden= 1 )
        v1.addstr( st )
        v1.refresh()

        #p1.refresh(0, 0, 0, 0, 22, 80)
        #p2.refresh(0, 0, 22, 0, 24, 80)
    #raw_input()	

if __name__ == '__main__':
    curses.wrapper(main)
