# -*- coding: iso-8859-15 -*-


# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
#     Romain Chantereau <rchantereau@entrouvert.com>
#     Nicolas Clapiès <nclapies@easter-eggs.org>
#     Pierre-Antoine Dejace <padejace@entrouvert.be>
#     Thierry Dulieu <tdulieu@easter-eggs.com>
#     Florent Monnier <monnier@codelutin.com>
#     Cédric Musso <cmusso@easter-eggs.org>
#     Frédéric Péters <fpeters@entrouvert.be>
#     Benjamin Poussin <poussin@codelutin.com>
#     Emmanuel Raviart <eraviart@entrouvert.com>
#     Sébastien Régnier <regnier@codelutin.com>
#     Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
#     Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
#     Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
#     Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
#     Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
#     Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program 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
# of the License, or (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


from glasnost.common.tools import *
import glasnost.common.tools_new as commonTools

from glasnost.proxy.tools import getProxyForServerRole, getProxy

from glasnost.web.WebAPI import GlasnostObject

from ObjectsCurses import CursesScreen
from tools import *

import curses

class CursesHierRubric:
    def __init__(self, rubric, level):
        self.rubric = rubric
        self.level = level
        self.expanded = 1
        if not hasattr(self.rubric, 'membersSet') or not self.rubric.membersSet:
            self.rubric.membersSet = []
        if not hasattr(self.rubric, 'contentId'):
            self.rubric.contentId = None


class RubricsScreen(CursesScreen):
    
    def __init__(self, stdscr):
        CursesScreen.__init__(self, stdscr)
        self.loadRubrics()
        self.keys = {
            curses.KEY_UP:    [ self.handleUp,   'Haut' ],
            curses.KEY_DOWN:  [ self.handleDown, 'Bas' ],
            curses.KEY_LEFT:  [ self.handleLeft, 'Vers la gauche' ],
            curses.KEY_RIGHT: [ self.handleRight,'Vers la droite' ],
            'k':              [ self.moveDown,   'Descendre sélection' ],
            'j':              [ self.moveUp,     'Monter sélection' ],
            'w':              [ self.write,      'Enregistrer' ],
            'q':              [ self.quit,       'Quitter' ],
            'E':              [ self.editContent,'Créer/Éditer article \'contentId\'' ],
            'v':              [ self.viewRubric, 'Vue rubrique' ],
        }

        self.topLine = 0
        self.selectedLine = 0
    
    def buildHier(self, rubric, level):
        if rubric in [x.rubric for x in self.rubrics]:
            cR = CursesHierRubric(rubric, level)
            cR.expanded = 0
            self.rubrics.append(cR)
            return
        self.rubrics.append( CursesHierRubric(rubric, level) )
        if not hasattr(rubric, 'membersSet'):
            return
        for r in rubric.membersSet:
            if commonTools.extractRole(r) != 'rubrics':
                continue
            r = [ x for x in self.rubricsL if x.id == r ][0]
            self.buildHier(r, level+1)

    def loadRubrics(self):
        rubricsProxy = getProxyForServerRole('rubrics')
        try:
            self.mainRubric = rubricsProxy.getMainObject()
        except faults.MissingMainRubric:
            self.mainRubric = None
        self.rubricsL = rubricsProxy.getObjects().values()
        self.rubrics = []
        if self.mainRubric:
            self.buildHier(self.mainRubric, -1)
        del self.rubrics[0]

        for r in self.rubricsL:
            if r.id in [ x.rubric.id for x in self.rubrics ] or \
                    self.mainRubric and r.id == self.mainRubric.id:
                continue
            self.rubrics.append( CursesHierRubric(r, -1) )

    def view(self, height, width):
        self.height = height

        if len(self.rubrics) == 0:
            return
        
        currentRubric = self.rubrics[self.selectedLine]

        for i, r in zip(range(height-4),
                self.rubrics[self.topLine:self.topLine+height-4]):
            options = 0
            if r is currentRubric:
                options = curses.color_pair(2) | curses.A_BOLD
            state = (r.expanded and ' ') or '+'
            if r.level == -1:
                name = '!%c  %s' % (state, r.rubric.name)
            else:
                name = ' %c  %s%s' % (state, '  '*r.level, r.rubric.name)
            self.stdscr.addstr(1+i, 0, name.ljust(width), options)
        
        statusLine = '%s  %s' % (
            currentRubric.rubric.id.ljust(width-17),
            (currentRubric.rubric.contentId and \
             'contentId: %3d' % int(commonTools.extractLocalId(currentRubric.rubric.contentId)))
              or '')
        self.stdscr.addstr(height-1, 0, statusLine.ljust(width-1))
        

    def handleUp(self):
        if self.selectedLine == 0:
            return
        self.selectedLine -= 1
        if self.selectedLine - self.topLine < 0:
            self.topLine -= 1
    
    def handleDown(self):
        if self.selectedLine+1 == len(self.rubrics):
            return
        self.selectedLine += 1
        if self.selectedLine - self.topLine >= self.height-1:
            self.topLine += 1

    def handleLeft(self):
        currentRubric = self.rubrics[self.selectedLine]
        currentIndent = currentRubric.level

        if currentIndent == -1:
            return

        if self.selectedLine != len(self.rubrics)-1 and \
                    self.rubrics[self.selectedLine+1].level > currentIndent:
            return # cancelled (next line has greater indent)
            
        wantedIndent = currentIndent - 1
        if wantedIndent == -1:
            # back to the end
            l = len(self.rubrics)
            self.rubrics.append(currentRubric)
            del self.rubrics[self.selectedLine]
        currentRubric.level = wantedIndent

    def handleRight(self):
        currentRubric = self.rubrics[self.selectedLine]
        currentIndent = currentRubric.level

        if currentIndent == -1:
            i = 0
            while i < len(self.rubrics) and self.rubrics[i].level > -1:
                i += 1
            self.rubrics[i], self.rubrics[self.selectedLine] = \
                        self.rubrics[self.selectedLine], self.rubrics[i]
            currentRubric.level = 0
            return

        if self.selectedLine == 0 and currentIndent != -1:
            return
        
        if self.rubrics[self.selectedLine-1].level < currentIndent:
            return

        currentRubric.level += 1
    
    def saveLevel(self, r, start, indent):
        i = start
        if not hasattr(r, 'membersSet'):
            r.membersSet = []
        r.membersSet = [ x for x in r.membersSet if \
                commonTools.extractRole(x) != 'rubrics' ]
        for r2 in self.rubrics[start:]:
            i += 1
            if r2.level == indent:
                r.membersSet.append(r2.rubric.id)
                if not r2.expanded:
                    continue
                self.saveLevel(r2.rubric, i, indent+1)
            if r2.level < indent:
                break
        
    def write(self):
        rubricsProxy = getProxyForServerRole('rubrics')
        if self.mainRubric:
            self.saveLevel(self.mainRubric, 0, 0)
        for r in [self.mainRubric] + [x.rubric for x in self.rubrics]:
            if not r:
                continue
            rubricsProxy.modifyObject(r)

    def quit(self):
        context.setVar('screens', context.getVar('screens')[:-1])

    def moveDown(self):
        i = self.selectedLine
        currentRubric = self.rubrics[i]
        if currentRubric.level == -1:
            return
        if i == len(self.rubrics)-1 or self.rubrics[i+1].level == -1:
            return
        self.rubrics[i], self.rubrics[i+1] = self.rubrics[i+1], self.rubrics[i]
        self.selectedLine = i+1
        if self.selectedLine == len(self.rubrics)-1:
            currentRubric.level = 0
        else:
            currentRubric.level = self.rubrics[i].level

    def moveUp(self):
        currentRubric = self.rubrics[self.selectedLine]
        if currentRubric.level == -1:
            return
        if self.selectedLine == 0:
            return
        i = self.selectedLine
        self.rubrics[i], self.rubrics[i-1] = self.rubrics[i-1], self.rubrics[i]
        self.selectedLine = i-1
        if self.selectedLine == 0:
            currentRubric.level = 0
        else:
            currentRubric.level = self.rubrics[i].level

    def editContent(self):
        currentRubric = self.rubrics[self.selectedLine]
        if currentRubric.rubric.contentId:
            articleId = currentRubric.rubric.contentId
            proxy = getProxy(articleId)
            article = proxy.getObject(articleId)
            newBody = editText(article.body)
            if newBody != article.body:
                article.body = newBody
                proxy.modifyObject(article)
        else:
            article = commonTools.newThing('object', 'articles.Article')
            article.language = 'fr'
            article.title = currentRubric.rubric.name
            article.authorsSet = context.getVar('userId')
            article.writersSet = [ article.authorsSet ]
            article.format = 'spip'
            article.body = editText()
            if article.body:
                currentRubric.rubric.contentId = proxy.addObject(article)
                
    def viewRubric(self):
        currentRubric = self.rubrics[self.selectedLine]
        context.getVar('screens').append(RubricScreen(currentRubric.rubric, self.stdscr))
        

class RubricScreen(CursesScreen):
    tabIndex = -1
    
    def __init__(self, rubric, stdscr):
        CursesScreen.__init__(self, stdscr)
        self.keys = {
            curses.KEY_UP:    [ self.handleUp,    'Haut'],
            curses.KEY_DOWN:  [ self.handleDown,  'Bas'],
            'e':              [ self.edit,        'Éditer' ],
            '\t':             [ self.handleTab,   '' ],
            '\n':             [ self.handleEnter, '' ],
            'N':              [ self.changePageName, 'Changement nom de page'],
            'T':              [ self.changePageNameArticle, 'idem pour article'],
            'q':              [ self.quit,        'Quitter' ],
        }
        self.rubric = rubric
        self.objects = [ GlasnostObject(x) for x in rubric.membersSet \
                            if commonTools.extractRole(x) != 'rubrics' ]

        height, width = self.stdscr.getmaxyx()
        for i in range(1, height-3):
            self.stdscr.addstr(i, 0, ' '*width)

        self.topLine = 0
        self.selectedLine = 0
    
    
    def view(self, height, width):
        self.height = height
        self.width = width

        name = '   Nom: %s' % self.rubric.name
        self.stdscr.addstr(2, 0, name.ljust(width))
        if self.tabIndex == 0:
            self.stdscr.addstr(2, 0, 'o', curses.A_BOLD)
        else:
            self.stdscr.addstr(2, 0, ' ', curses.A_BOLD)

        if not self.objects:
            self.stdscr.addstr(height-1, width-1, '')
            self.stdscr.addstr(self.height-1, 0, ' '*(self.width-1))
            return
          
        currentObject = self.objects[self.selectedLine]

        for i, o in zip(range(height-7),
                self.objects[self.topLine:self.topLine+height-7]):
            name = '  %s' % o.label
            options = 0
            if i == self.selectedLine:
                options = curses.color_pair(2) | curses.A_BOLD
            self.stdscr.addstr(4+i, 0, name.ljust(width), options)

        self.stdscr.addstr(height-1, 0, currentObject.id.ljust(width-1))

    
    def quit(self):
        context.setVar('screens', context.getVar('screens')[:-1])
    
    def handleUp(self):
        if self.selectedLine == 0:
            return
        self.selectedLine -= 1
        if self.selectedLine - self.topLine < 0:
            self.topLine -= 1
    
    def handleDown(self):
        if self.selectedLine+1 == len(self.objects):
            return
        self.selectedLine += 1
        if self.selectedLine - self.topLine >= self.height-1:
            self.topLine += 1

    def edit(self):
        currentObject = self.objects[self.selectedLine]
        articleId = currentObject.objectId
        proxy = getProxy(articleId)
        article = proxy.getObject(articleId)
        newBody = editText(article.body)
        if newBody != article.body:
            article.body = newBody
            proxy.modifyObject(article)

    def handleTab(self):
        # should be moved to a parent class
        if self.tabIndex == -1:
            self.tabIndex = 0
        else:
            self.tabIndex += 1
            if self.tabIndex > 0:
                self.tabIndex = 0
        
    def handleEnter(self):
        if self.tabIndex == 0:
            self.stdscr.addstr(self.height-1, 0, 'Nouveau nom: '.ljust(self.width-1))
            curses.echo()
            name = self.stdscr.getstr(self.height-1, 13, 40)
            curses.noecho()
            if name:
                self.rubric.name = name

    def changePageName(self):
        pagenameProxy = getProxyForServerRole('pagenames')
        pagename = commonTools.newThing('object', 'pagenames.PageName')

        self.stdscr.addstr(self.height-1, 0, 'Nom de page: '.ljust(self.width-1))
        curses.echo()
        pagename.name = self.stdscr.getstr(self.height-1, 13, 40)
        curses.noecho()
        pagename.mappedId = self.rubric.id
        pagenameId = pagenameProxy.addObject(pagename)

    def changePageNameArticle(self):
        currentObject = self.objects[self.selectedLine]
        pagenameProxy = getProxyForServerRole('pagenames')
        pagename = commonTools.newThing('object', 'pagenames.PageName')

        self.stdscr.addstr(self.height-1, 0, 'Nom de page: '.ljust(self.width-1))
        curses.echo()
        pagename.name = self.stdscr.getstr(self.height-1, 13, 40)
        curses.noecho()
        pagename.mappedId = currentObject.id
        pagenameId = pagenameProxy.addObject(pagename)

