#
# language.py: install data component that stores information about both
#              installer runtime language choice and installed system
#              language support.
#
# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2009  Red Hat, Inc.
# All rights reserved.
#
# 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, see <http://www.gnu.org/licenses/>.
#

import os
import string
import locale

import gettext
from simpleconfig import SimpleConfigFile
import system_config_keyboard.keyboard as keyboard

import logging
log = logging.getLogger("anaconda")

# Converts a single language into a "language search path". For example,
# fr_FR.utf8@euro would become "fr_FR.utf8@eueo fr_FR.utf8 fr_FR fr"
def expandLangs(astring):
    langs = [astring]
    charset = None
    base = None

    # remove charset ...
    if '.' in astring:
        langs.append(string.split(astring, '.')[0])

    if '@' in astring:
        charset = string.split(astring, '@')[1]

    if '_' in astring:
        base = string.split(astring, '_')[0]

        if charset:
            langs.append("%s@%s" % (base, charset))

        langs.append(base)
    else:
        langs.append(astring[:2])

    return langs

class Language(object):
    def _setInstLang(self, value):
        # Always store in its full form so we know what we're comparing with.
        try:
            self._instLang = self._canonLang(value)
        except ValueError:
            # If the language isn't listed in lang-table, we won't know what
            # keyboard/font/etc. to use.  However, we can still set the $LANG
            # to that and make sure it works in the installed system.
            self._instLang = value

        # If we're running in text mode, value may not be a supported language
        # to display.  We need to default to en_US.UTF-8 for now.
        if self.displayMode == 't':
            for (lang, info) in self.localeInfo.iteritems():
                # If there's no font, it's not a supported language.
                if lang == self._instLang and info[2] == "none":
                    self._instLang = self._default
                    break

        # Now set some things to make sure the language setting takes effect
        # right now.
        os.environ["LANG"] = self._instLang
        os.environ["LC_NUMERIC"] = "C"

        try:
            locale.setlocale(locale.LC_ALL, "")
        except locale.Error:
            pass

        # XXX: oh ick.  this is the sort of thing which you should never do...
        # but we switch languages at runtime and thus need to invalidate
        # the set of languages/mofiles which gettext knows about
        gettext._translations = {}

    def _getInstLang(self):
        # If we were given a language that's not in lang-table, lie and say
        # we're using the default.  This prevents us from having to check all
        # over the place.  Unfortunately, it also means anaconda will be
        # running with the wrong font and keyboard in these cases.
        if self._instLang in self.localeInfo.keys():
            return self._instLang
        else:
            return self._default

    # The language being displayed while anaconda is running.
    instLang = property(lambda s: s._getInstLang(), lambda s, v: s._setInstLang(v))

    def _setSystemLang(self, value):
        # Always store in its full form so we know what we're comparing with.
        try:
            self._systemLang = self._canonLang(value)
        except ValueError:
            # If the language isn't listed in lang-table, we won't know what
            # keyboard/font/etc. to use.  However, we can still set the $LANG
            # to that and make sure it works in the installed system.
            self._systemLang = value

        # Now set a bunch of other things that'll get written to
        # /etc/sysconfig/i18n on the installed system.
        self.info["LANG"] = self._systemLang

        if not self.localeInfo.has_key(self._systemLang):
            return

        if self.localeInfo[self._systemLang][2] == "none":
            self.info["SYSFONT"] = None
        else:
            self.info["SYSFONT"] = self.localeInfo[self._systemLang][2]

        # XXX hack - because of exceptional cases on the var - zh_CN.GB2312
        if self._systemLang == "zh_CN.GB18030":
            self.info["LANGUAGE"] = "zh_CN.GB18030:zh_CN.GB2312:zh_CN"

    # The language to use on the installed system.  This can differ from the
    # language being used during anaconda.  For instance, text installs cannot
    # display all languages (CJK, Indic, etc.).
    systemLang = property(lambda s: s._systemLang, lambda s, v: s._setSystemLang(v))

    def __init__ (self, display_mode = 'g'):
        self._default = "en_US.UTF-8"
        self.displayMode = display_mode
        self.info = {}
        self.localeInfo = {}
        self.nativeLangNames = {}

        # English name -> native name mapping
        search = ('lang-names', '/usr/lib/anaconda/lang-names')
        for path in search:
            if os.access(path, os.R_OK):
                f = open(path, 'r')
                for line in f.readlines():
                    lang, native = string.split(line, '\t')
                    native = native.strip()
                    self.nativeLangNames[lang] = native

                f.close()
                break

        # nick -> (name, short name, font, keyboard, timezone) mapping
        search = ('lang-table', '/tmp/updates/lang-table', '/etc/lang-table',
                  '/usr/lib/anaconda/lang-table')
        for path in search:
            if os.access(path, os.R_OK):
                f = open(path, "r")
                for line in f.readlines():
                    string.strip(line)
                    l = string.split(line, '\t')

                    # throw out invalid lines
                    if len(l) < 6:
                        continue

                    self.localeInfo[l[3]] = (l[0], l[1], l[2], l[4], string.strip(l[5]))

                f.close()
                break

        # Hard code this to prevent errors in the build environment.
        self.localeInfo['C'] = self.localeInfo[self._default]

        # instLang must be set after localeInfo is populated, in case the
        # current setting is unsupported by anaconda..
        self.instLang = os.environ.get("LANG", self._default)
        self.systemLang = os.environ.get("LANG", self._default)

    def _canonLang(self, lang):
        """Convert the shortened form of a language name into the full
           version.  If it's not found, raise ValueError.

           Example:  fr    -> fr_FR.UTF-8
                     fr_FR -> fr_FR.UTF-8
                     fr_CA -> ValueError
        """
        for key in self.localeInfo.keys():
            if lang in expandLangs(key):
                return key

        raise ValueError

    def available(self):
        return self.nativeLangNames.keys()

    def dracutSetupString(self):
        args=""

        for (key, val) in self.info.iteritems():
            if val != None:
                args += " %s=%s" % (key, val)

        return args

    def getCurrentLangSearchList(self):
        return expandLangs(self.systemLang) + ['C']

    def getDefaultKeyboard(self, instPath):
        try:
            return self.localeInfo[self.systemLang][3]
        except KeyError:
            try:
                kbd = keyboard.Keyboard()
                kbd.read(instPath)
                return kbd.get()
            except:
                return self.localeInfo[self._default][3]

    def getDefaultTimeZone(self, instPath):
        try:
            return self.localeInfo[self.systemLang][4]
        except KeyError:
            # If doing an upgrade and the system language is something not
            # recognized by anaconda, we should try to see if we can figure
            # it out from the running system.
            if os.path.exists(instPath + "/etc/sysconfig/clock"):
                cfg = SimpleConfigFile()
                cfg.read(instPath + "/etc/sysconfig/clock")

                try:
                    return cfg.get("ZONE")
                except:
                    return self.localeInfo[self._default][4]
            else:
                return self.localeInfo[self._default][4]

    def getFontFile(self, lang):
        # Note: in /etc/fonts.cgz fonts are named by the map
        # name as that's unique, font names are not
        try:
            l = self._canonLang(lang)
        except ValueError:
            l = self._default

        return self.localeInfo[l][2]

    def getLangName(self, lang):
        try:
            l = self._canonLang(lang)
        except ValueError:
            l = self._default

        return self.localeInfo[l][0]

    def getLangByName(self, name):
        for (key, val) in self.localeInfo.iteritems():
            if val[0] == name:
                return key

    def getNativeLangName(self, lang):
        return self.nativeLangNames[lang]

    def write(self, instPath):
        f = open(instPath + "/etc/sysconfig/i18n", "w")

        for (key, val) in self.info.iteritems():
            if val != None:
                f.write("%s=\"%s\"\n" % (key, val))

        f.close()

    def writeKS(self, f):
        f.write("lang %s\n" % self.info['LANG'])