#
# text.py - text mode frontend to anaconda
#
# Erik Troan <[email protected]>
# Matt Wilson <[email protected]>
#
# Copyright 1999-2002 Red Hat, Inc.
#
# This software may be freely redistributed under the terms of the GNU
# library public license.
#
# You should have received a copy of the GNU Library Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from snack import *
import sys
import os
import isys
import iutil
import time
import signal
import parted
import string
import kudzu
from language import expandLangs
from flags import flags
from constants_text import *
from constants import *

from rhpl.log import log
from rhpl.translate import _, cat, N_

stepToClasses = {
   "language" : ("language_text", "LanguageWindow"),
   "keyboard" : ("keyboard_text", "KeyboardWindow"),
   "mouse" : ("mouse_text", ("MouseWindow", "MouseDeviceWindow")),
   "welcome" : ("welcome_text", "WelcomeWindow"),
   "installtype" : ("installpath_text", "InstallPathWindow"),
   "autopartition" : ("partition_text", "AutoPartitionWindow"),
   "custom-upgrade" : ("upgrade_text", "UpgradeExamineWindow"),
   "addswap" : ("upgrade_text", "UpgradeSwapWindow"),
   "upgrademigratefs" : ("upgrade_text", "UpgradeMigrateFSWindow"),
   "fdisk" : ("fdisk_text", "fdiskPartitionWindow"),
   "partitionmethod" : ("partmethod_text", ("PartitionMethod")),
   "partition": ("partition_text", ("PartitionWindow")),
   "findinstall" : ("upgrade_text", "UpgradeExamineWindow"),
   "addswap" : ("upgrade_text", "UpgradeSwapWindow"),
   "upgbootloader": ("upgrade_bootloader_text", "UpgradeBootloaderWindow"),
   "bootloader" : ("bootloader_text", ("BootloaderChoiceWindow",
                                       "BootloaderAppendWindow",
                                       "BootloaderPasswordWindow")),
   "bootloaderadvanced" : ("bootloader_text", ("BootloaderImagesWindow",
                                               "BootloaderLocationWindow")),
   "network" : ("network_text", ("NetworkDeviceWindow", "NetworkGlobalWindow",
                                 "HostnameWindow")),
   "firewall" : ("firewall_text", "FirewallWindow"),
   "languagesupport" : ("language_text", ("LanguageSupportWindow",
                                          "LanguageDefaultWindow")),
   "timezone" : ("timezone_text", "TimezoneWindow"),
   "accounts" : ("userauth_text", "RootPasswordWindow"),
   "authentication" : ("userauth_text", ("AuthConfigWindow")),
   "desktopchoice": ("desktop_choice_text", "DesktopChoiceWindow"),
   "package-selection"  : ("packages_text", "PackageGroupWindow"),
   "indivpackage" : ("packages_text", ("IndividualPackageWindow")),
   "dependencies" : ("packages_text", "PackageDepWindow"),
   "videocard" : ("xconfig_text", "XConfigWindowCard"),
   "monitor" : ("xconfig_text", "MonitorWindow"),
   "xcustom" : ("xconfig_text", "XCustomWindow"),
   "confirminstall" : ("confirm_text", "BeginInstallWindow"),
   "confirmupgrade" : ("confirm_text", "BeginUpgradeWindow"),
   "install" : ("progress_text", "setupForInstall"),
   "bootdisk" : ("bootdisk_text", ("BootDiskWindow")),
   "complete" : ("complete_text", "FinishedWindow"),
}

if iutil.getArch() == 'sparc':
   stepToClasses["bootloader"] = ("silo_text", ("SiloAppendWindow",
                                                "SiloWindow"
                                                "SiloImagesWindow"))
if iutil.getArch() == 's390':
   stepToClasses["bootloader"] = ("zipl_text", ( "ZiplWindow"))

class InstallWindow:
   def __call__ (self, screen):
       raise RuntimeError, "Unimplemented screen"

class WaitWindow:
   def pop(self):
       self.screen.popWindow()
       self.screen.refresh()

   def __init__(self, screen, title, text):
       self.screen = screen
       width = 40
       if (len(text) < width): width = len(text)

       t = TextboxReflowed(width, text)

       g = GridForm(self.screen, title, 1, 1)
       g.add(t, 0, 0)
       g.draw()
       self.screen.refresh()

class OkCancelWindow:
   def getrc(self):
       return self.rc

   def __init__(self, screen, title, text):
       rc = ButtonChoiceWindow(screen, title, text,
                               buttons=[TEXT_OK_BUTTON, _("Cancel")])
       if rc == string.lower(_("Cancel")):
           self.rc = 1
       else:
           self.rc = 0

class ProgressWindow:
   def pop(self):
       self.screen.popWindow()
       self.screen.refresh()
       del self.scale
       self.scale = None

   def set(self, amount):
       self.scale.set(amount)
       self.screen.refresh()

   def __init__(self, screen, title, text, total):
       self.screen = screen
       width = 55
       if (len(text) > width): width = len(text)

       t = TextboxReflowed(width, text)

       g = GridForm(self.screen, title, 1, 2)
       g.add(t, 0, 0, (0, 0, 0, 1), anchorLeft=1)

       self.scale = Scale(width, total)
       g.add(self.scale, 0, 1)

       g.draw()
       self.screen.refresh()

class InstallInterface:
   def helpWindow(self, screen, key):
       lang = self.instLanguage.getCurrent()
       lang = self.instLanguage.getLangNick(lang)
       self.langSearchPath = expandLangs(lang) + ['C']

       if key == "helponhelp":
           if self.showingHelpOnHelp:
               return None
           else:
               self.showingHelpOnHelp = 1
       try:
           f = None

           if self.configFileData.has_key("helptag"):
               helpTag = "-%s" % (self.configFileData["helptag"],)
           else:
               helpTag = ""
           arch = "-%s" % (iutil.getArch(),)
           tags = [ "%s%s" % (helpTag, arch), "%s" % (helpTag,),
                    "%s" % (arch,), "" ]

           # XXX
           #
           # HelpWindow can't get to the langauge

           found = 0
           for path in ("./text-", "/mnt/source/RHupdates/",
                        "/usr/share/anaconda/"):
               if found:
                   break
               for lang in self.langSearchPath:
                   for tag in tags:
                       fn = "%shelp/%s/s1-help-screens-%s%s.txt" \
                            % (path, lang, key, tag)

                       try:
                           f = open(fn)
                       except IOError, msg:
                           continue
                       found = 1
                       break

           if not f:
               ButtonChoiceWindow(screen, _("Help not available"),
                                  _("No help is available for this "
                                    "step of the install."),
                                  buttons=[TEXT_OK_BUTTON])
               return None

           lines = f.readlines()
           for l in lines:
               l = l.replace("@RHL@", productName)
               l = l.replace("@RHLVER@", productVersion)
           while not string.strip(l[0]):
               l = l[1:]
           title = string.strip(l[0])
           l = l[1:]
           while not string.strip(l[0]):
               l = l[1:]
           f.close()

           height = 10
           scroll = 1
           if len(l) < height:
               height = len(l)
               scroll = 0

           width = len(title) + 6
           stream = ""
           for line in l:
               line = string.strip(line)
               stream = stream + line + "\n"
               if len(line) > width:
                   width = len(line)

           bb = ButtonBar(screen, [TEXT_OK_BUTTON])
           t = Textbox(width, height, stream, scroll=scroll)

           g = GridFormHelp(screen, title, "helponhelp", 1, 2)
           g.add(t, 0, 0, padding=(0, 0, 0, 1))
           g.add(bb, 0, 1, growx=1)

           g.runOnce()
           self.showingHelpOnHelp = 0
       except:
           import traceback
           (type, value, tb) = sys.exc_info()
           from string import joinfields
           list = traceback.format_exception(type, value, tb)
           text = joinfields(list, "")
           rc = self.exceptionWindow(_("Exception Occurred"), text)
           if rc:
               import pdb
               pdb.post_mortem(tb)
           os._exit(1)

   def progressWindow(self, title, text, total):
       return ProgressWindow(self.screen, title, text, total)

   def messageWindow(self, title, text, type="ok", default = None,
                     custom_icon=None, custom_buttons=[]):
       if type == "ok":
           ButtonChoiceWindow(self.screen, title, text,
                              buttons=[TEXT_OK_BUTTON])
       elif type == "yesno":
           if default and default == "no":
               btnlist = [TEXT_NO_BUTTON, TEXT_YES_BUTTON]
           else:
               btnlist = [TEXT_YES_BUTTON, TEXT_NO_BUTTON]
           rc = ButtonChoiceWindow(self.screen, title, text,
                              buttons=btnlist)
           if rc == "yes":
               return 1
           else:
               return 0
       elif type == "custom":
           tmpbut = []
           for but in custom_buttons:
               tmpbut.append(string.replace(but,"_",""))

           rc = ButtonChoiceWindow(self.screen, title, text, width=60,
                                   buttons=tmpbut)

           idx = 0
           for b in tmpbut:
               if string.lower(b) == rc:
                   return idx != 0
               idx = idx + 1
           return 0
       else:
           return OkCancelWindow(self.screen, title, text)

   def dumpWindow(self):
       rc = ButtonChoiceWindow(self.screen, _("Save Crash Dump"),
           _("Please insert a floppy now. All contents of the disk "
             "will be erased, so please choose your diskette carefully."),
           [TEXT_OK_BUTTON, _("Cancel")])

       if rc == string.lower(_("Cancel")):
           return 1

       return 0

   def exceptionWindow(self, title, text):
       try:
           floppyDevices = 0
           for dev in kudzu.probe(kudzu.CLASS_FLOPPY, kudzu.BUS_UNSPEC,
                                  kudzu.PROBE_ALL):
               if not dev.detached:
                   floppyDevices = floppyDevices + 1
       except:
           floppyDevices = 0
       if floppyDevices > 0 or DEBUG:
           ugh = "%s\n\n" % (exceptionText,)
           buttons=[TEXT_OK_BUTTON, _("Save"), _("Debug")]
       else:
           ugh = "%s\n\n" % (exceptionTextNoFloppy,)
           buttons=[TEXT_OK_BUTTON, _("Debug")]

       rc = ButtonChoiceWindow(self.screen, title, ugh + text, buttons)
       if rc == string.lower(_("Debug")):
           return 1
       elif rc == string.lower(_("Save")):
           return 2
       return None

   def partedExceptionWindow(self, exc):
       # if our only option is to cancel, let us handle the exception
       # in our code and avoid popping up the exception window here.
       if exc.options == parted.EXCEPTION_CANCEL:
           return parted.EXCEPTION_UNHANDLED
       buttons = []
       buttonToAction = {}
       flags = ((parted.EXCEPTION_FIX, N_("Fix")),
                (parted.EXCEPTION_YES, N_("Yes")),
                (parted.EXCEPTION_NO, N_("No")),
                (parted.EXCEPTION_OK, N_("OK")),
                (parted.EXCEPTION_RETRY, N_("Retry")),
                (parted.EXCEPTION_IGNORE, N_("Ignore")),
                (parted.EXCEPTION_CANCEL, N_("Cancel")))
       for flag, errorstring in flags:
           if exc.options & flag:
               buttons.append(_(errorstring))
               buttonToAction[string.lower(_(errorstring))] = flag

       rc = None
       while not buttonToAction.has_key(rc):
           rc = ButtonChoiceWindow(self.screen, exc.type_string, exc.message,
                                   buttons=buttons)

       return buttonToAction[rc]


   def waitWindow(self, title, text):
       return WaitWindow(self.screen, title, text)

   def drawFrame(self):
       self.welcomeText = _("%s ") % (productName,)
       self.screen.drawRootText (0, 0, self.welcomeText)
       self.screen.drawRootText (len(_(self.welcomeText)), 0,
                                 (self.screen.width -
                                  len(_(self.welcomeText))) * " ")

       if (os.access("/usr/share/anaconda/help/C/s1-help-screens-lang.txt", os.R_OK)):
           self.screen.pushHelpLine(_(" <F1> for help | <Tab> between elements | <Space> selects | <F12> next screen"))
       else:
           self.screen.pushHelpLine(_("  <Tab>/<Alt-Tab> between elements   |  <Space> selects   |  <F12> next screen"))

   def setScreen(self, screen):
       self.screen = screen

   def shutdown(self):
       self.screen.finish()
       self.screen = None

   def __init__(self):
       signal.signal(signal.SIGINT, signal.SIG_IGN)
       signal.signal(signal.SIGTSTP, signal.SIG_IGN)
       self.screen = None
       self.showingHelpOnHelp = 0

   def __del__(self):
       if self.screen:
           self.screen.finish()

   def run(self, id, dispatch, configFileData):
       # set up for CJK text mode if needed
       if (flags.setupFilesystems and
           (id.instLanguage.getFontFile(id.instLanguage.getCurrent()) == "bterm")
           and not isys.isPsudoTTY(0)
           and not flags.serial):
           log("starting bterm")
           try:
               rc = isys.startBterm()
               time.sleep(1)
           except Exception, e:
               log("got an exception starting bterm: %s" %(e,))

       self.screen = SnackScreen()
       self.configFileData = configFileData
       self.screen.helpCallback(self.helpWindow)

# uncomment this line to make the installer quit on <Ctrl+Z>
# handy for quick debugging.
#       self.screen.suspendCallback(killSelf, self.screen)
# uncomment this line to drop into the python debugger on <Ctrl+Z>
# --VERY handy--
       if DEBUG or flags.test:
           self.screen.suspendCallback(debugSelf, self.screen)

       if flags.serial or isys.isPsudoTTY(0) or isys.isVioConsole():
           self.screen.suspendCallback(spawnShell, self.screen)

       # clear out the old root text by writing spaces in the blank
       # area on the right side of the screen
       #self.screen.drawRootText (len(_(self.welcomeText)), 0,
                 #(self.screen.width - len(_(self.welcomeText))) * " ")
       #self.screen.drawRootText (0 - len(_(step[0])), 0, _(step[0]))
       langname = id.instLanguage.getCurrent()
       lang = id.instLanguage.getLangNick(langname)

       self.langSearchPath = expandLangs(lang) + ['C']
       self.instLanguage = id.instLanguage

       # draw the frame after setting up the fallback
       self.drawFrame()

       # draw the frame after setting up the fallback
       self.drawFrame()

       id.fsset.registerMessageWindow(self.messageWindow)
       id.fsset.registerProgressWindow(self.progressWindow)
       id.fsset.registerWaitWindow(self.waitWindow)
       parted.exception_set_handler(self.partedExceptionWindow)

       lastrc = INSTALL_OK
       (step, args) = dispatch.currentStep()
       while step:
           (file, classNames) = stepToClasses[step]

           if type(classNames) != type(()):
               classNames = (classNames,)

           if lastrc == INSTALL_OK:
               step = 0
           else:
               step = len(classNames) - 1

           while step >= 0 and step < len(classNames):
               # reget the args.  they could change (especially direction)
               (foo, args) = dispatch.currentStep()

               nextWindow = None
               s = "from %s import %s; nextWindow = %s" % \
                       (file, classNames[step], classNames[step])
               exec s

               win = nextWindow()

               #log("TUI running step %s (class %s, file %s)" %
                           #(step, file, classNames))

               rc = apply(win, (self.screen, ) + args)

               if rc == INSTALL_NOOP:
                   rc = lastrc

               if rc == INSTALL_BACK:
                   step = step - 1
                   dispatch.dir = DISPATCH_BACK
               elif rc == INSTALL_OK:
                   step = step + 1
                   dispatch.dir = DISPATCH_FORWARD

               lastrc = rc

           if step == -1:
               if not dispatch.canGoBack():
                   ButtonChoiceWindow(self.screen, _("Cancelled"),
                                      _("I can't go to the previous step "
                                        "from here. You will have to try "
                                        "again."),
                                      buttons=[_("OK")])
               dispatch.gotoPrev()
           else:
               dispatch.gotoNext()

           (step, args) = dispatch.currentStep()

       self.screen.finish()

def killSelf(screen):
   screen.finish()
   os._exit(0)

def debugSelf(screen):
   screen.suspend()
   import pdb
   try:
       pdb.set_trace()
   except:
       sys.exit(-1)
   screen.resume()

def spawnShell(screen):
   screen.suspend()
   print "\n\nType <exit> to return to the install program.\n"
   iutil.execWithRedirect("/bin/sh", ["-/bin/sh"])
   time.sleep(5)
   screen.resume()