# -*- coding:utf-8 -*-
## src/common/check_paths.py
##
## Copyright (C) 2005-2006 Travis Shirk <travis AT pobox.com>
##                         Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2005-2014 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2006 Dimitur Kirov <dkirov AT gmail.com>
## Copyright (C) 2007 Tomasz Melcer <liori AT exroot.org>
## Copyright (C) 2008 Jean-Marie Traissard <jim AT lapin.org>
##
## This file is part of Gajim.
##
## Gajim 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; version 3 only.
##
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
##

import os
import shutil
import sys

from gajim.common import app
from gajim.common import logger

# DO NOT MOVE ABOVE OF import gajim
import sqlite3 as sqlite

def create_log_db():
    print(_('creating logs database'))
    con = sqlite.connect(logger.LOG_DB_PATH)
    os.chmod(logger.LOG_DB_PATH, 0o600) # rw only for us
    cur = con.cursor()
    # create the tables
    # kind can be
    # status, gcstatus, gc_msg, (we only recv for those 3),
    # single_msg_recv, chat_msg_recv, chat_msg_sent, single_msg_sent
    # to meet all our needs
    # logs.jid_id --> jids.jid_id but Sqlite doesn't do FK etc so it's done in python code
    # jids.jid text column will be JID if TC-related, room_jid if GC-related,
    # ROOM_JID/nick if pm-related.
    # also check optparser.py, which updates databases on gajim updates
    cur.executescript(
            '''
            CREATE TABLE jids(
                    jid_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
                    jid TEXT UNIQUE,
                    type INTEGER
            );

            CREATE TABLE unread_messages(
                    message_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
                    jid_id INTEGER,
                    shown BOOLEAN default 0
            );

            CREATE INDEX idx_unread_messages_jid_id ON unread_messages (jid_id);

            CREATE TABLE logs(
                    log_line_id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
                    account_id INTEGER,
                    jid_id INTEGER,
                    contact_name TEXT,
                    time INTEGER,
                    kind INTEGER,
                    show INTEGER,
                    message TEXT,
                    subject TEXT,
                    additional_data TEXT,
                    stanza_id TEXT,
                    encryption TEXT,
                    encryption_state TEXT,
                    marker INTEGER
            );

            CREATE TABLE last_archive_message(
                    jid_id INTEGER PRIMARY KEY UNIQUE,
                    last_mam_id TEXT,
                    oldest_mam_timestamp TEXT,
                    last_muc_timestamp TEXT
            );

            CREATE INDEX idx_logs_jid_id_time ON logs (jid_id, time DESC);
            '''
            )

    con.commit()
    con.close()

def create_cache_db():
    print(_('creating cache database'))
    con = sqlite.connect(logger.CACHE_DB_PATH)
    os.chmod(logger.CACHE_DB_PATH, 0o600) # rw only for us
    cur = con.cursor()
    cur.executescript(
            '''
            CREATE TABLE transports_cache (
                    transport TEXT UNIQUE,
                    type INTEGER
            );

            CREATE TABLE caps_cache (
                    hash_method TEXT,
                    hash TEXT,
                    data BLOB,
                    last_seen INTEGER);

            CREATE TABLE rooms_last_message_time(
                    jid_id INTEGER PRIMARY KEY UNIQUE,
                    time INTEGER
            );

            CREATE TABLE IF NOT EXISTS roster_entry(
                    account_jid_id INTEGER,
                    jid_id INTEGER,
                    name TEXT,
                    subscription INTEGER,
                    ask BOOLEAN,
                    avatar_sha TEXT,
                    PRIMARY KEY (account_jid_id, jid_id)
            );

            CREATE TABLE IF NOT EXISTS roster_group(
                    account_jid_id INTEGER,
                    jid_id INTEGER,
                    group_name TEXT,
                    PRIMARY KEY (account_jid_id, jid_id, group_name)
            );
            '''
            )

    con.commit()
    con.close()

def split_db():
    print('spliting database')
    if os.name == 'nt':
        try:
            OLD_LOG_DB_FOLDER = os.path.join(os.environ['appdata'], 'Gajim')
        except KeyError:
            OLD_LOG_DB_FOLDER = '.'
    else:
        OLD_LOG_DB_FOLDER = os.path.expanduser('~/.gajim')

    tmp = logger.CACHE_DB_PATH
    logger.CACHE_DB_PATH = os.path.join(OLD_LOG_DB_FOLDER, 'cache.db')
    create_cache_db()
    back = os.getcwd()
    os.chdir(OLD_LOG_DB_FOLDER)
    con = sqlite.connect('logs.db')
    os.chdir(back)
    cur = con.cursor()
    cur.execute('''SELECT name FROM sqlite_master WHERE type = 'table';''')
    tables = cur.fetchall() # we get [('jids',), ('unread_messages',), ...
    tables = [t[0] for t in tables]
    cur.execute("ATTACH DATABASE '%s' AS cache" % logger.CACHE_DB_PATH)
    for table in ('caps_cache', 'rooms_last_message_time', 'roster_entry',
    'roster_group', 'transports_cache'):
        if table not in tables:
            continue
        try:
            cur.executescript(
                    'INSERT INTO cache.%s SELECT * FROM %s;' % (table, table))
            con.commit()
            cur.executescript('DROP TABLE %s;' % table)
            con.commit()
        except sqlite.OperationalError as e:
            print('error moving table %s to cache.db: %s' % (table, str(e)),
                file=sys.stderr)
    con.close()
    logger.CACHE_DB_PATH = tmp

def check_and_possibly_move_config():
    LOG_DB_PATH = logger.LOG_DB_PATH
    CACHE_DB_PATH = logger.CACHE_DB_PATH
    vars = {}
    vars['VCARD_PATH'] = app.VCARD_PATH
    vars['AVATAR_PATH'] = app.AVATAR_PATH
    vars['MY_EMOTS_PATH'] = app.MY_EMOTS_PATH
    vars['MY_ICONSETS_PATH'] = app.MY_ICONSETS_PATH
    vars['MY_MOOD_ICONSETS_PATH'] = app.MY_MOOD_ICONSETS_PATH
    vars['MY_ACTIVITY_ICONSETS_PATH'] = app.MY_ACTIVITY_ICONSETS_PATH
    from gajim.common import configpaths
    MY_DATA = configpaths.gajimpaths['MY_DATA']
    MY_CONFIG = configpaths.gajimpaths['MY_CONFIG']
    MY_CACHE = configpaths.gajimpaths['MY_CACHE']

    if os.path.exists(LOG_DB_PATH):
        # File already exists
        return

    if os.name == 'nt':
        try:
            OLD_LOG_DB_FOLDER = os.path.join(os.environ['appdata'], 'Gajim')
        except KeyError:
            OLD_LOG_DB_FOLDER = '.'
    else:
        OLD_LOG_DB_FOLDER = os.path.expanduser('~/.gajim')
    if not os.path.exists(OLD_LOG_DB_FOLDER):
        return
    OLD_LOG_DB_PATH = os.path.join(OLD_LOG_DB_FOLDER, 'logs.db')
    OLD_CACHE_DB_PATH = os.path.join(OLD_LOG_DB_FOLDER, 'cache.db')
    vars['OLD_VCARD_PATH'] = os.path.join(OLD_LOG_DB_FOLDER, 'vcards')
    vars['OLD_AVATAR_PATH'] = os.path.join(OLD_LOG_DB_FOLDER, 'avatars')
    vars['OLD_MY_EMOTS_PATH'] = os.path.join(OLD_LOG_DB_FOLDER, 'emoticons')
    vars['OLD_MY_ICONSETS_PATH'] = os.path.join(OLD_LOG_DB_FOLDER, 'iconsets')
    vars['OLD_MY_MOOD_ICONSETS_PATH'] = os.path.join(OLD_LOG_DB_FOLDER, 'moods')
    vars['OLD_MY_ACTIVITY_ICONSETS_PATH'] = os.path.join(OLD_LOG_DB_FOLDER,
            'activities')
    OLD_CONFIG_FILES = []
    OLD_DATA_FILES = []
    for f in os.listdir(OLD_LOG_DB_FOLDER):
        if f == 'config' or f.startswith('config.'):
            OLD_CONFIG_FILES.append(f)
        if f == 'secrets' or f.startswith('secrets.'):
            OLD_DATA_FILES.append(f)
        if f == 'cacerts.pem':
            OLD_DATA_FILES.append(f)

    if not os.path.exists(OLD_LOG_DB_PATH):
        return

    if not os.path.exists(OLD_CACHE_DB_PATH):
        # split database
        split_db()

    to_move = {}
    to_move[OLD_LOG_DB_PATH] = LOG_DB_PATH
    to_move[OLD_CACHE_DB_PATH] = CACHE_DB_PATH

    for folder in ('VCARD_PATH', 'AVATAR_PATH', 'MY_EMOTS_PATH',
    'MY_ICONSETS_PATH', 'MY_MOOD_ICONSETS_PATH', 'MY_ACTIVITY_ICONSETS_PATH'):
        src = vars['OLD_' + folder]
        dst = vars[folder]
        to_move[src] = dst

    # move config files
    for f in OLD_CONFIG_FILES:
        src = os.path.join(OLD_LOG_DB_FOLDER, f)
        dst = os.path.join(MY_CONFIG, f)
        to_move[src] = dst

    # Move data files (secrets, cacert.pem)
    for f in OLD_DATA_FILES:
        src = os.path.join(OLD_LOG_DB_FOLDER, f)
        dst = os.path.join(MY_DATA, f)
        to_move[src] = dst

    for src, dst in to_move.items():
        if os.path.exists(dst):
            continue
        if not os.path.exists(src):
            continue
        print(_('moving %(src)s to %(dst)s') % {'src': src, 'dst': dst})
        shutil.move(src, dst)
    app.logger.init_vars()
    app.logger.attach_cache_database()

def check_and_possibly_create_paths():
    LOG_DB_PATH = logger.LOG_DB_PATH
    LOG_DB_FOLDER, LOG_DB_FILE = os.path.split(LOG_DB_PATH)

    CACHE_DB_PATH = logger.CACHE_DB_PATH
    CACHE_DB_FOLDER, CACHE_DB_FILE = os.path.split(CACHE_DB_PATH)

    VCARD_PATH = app.VCARD_PATH
    AVATAR_PATH = app.AVATAR_PATH
    from gajim.common import configpaths
    MY_DATA = configpaths.gajimpaths['MY_DATA']
    MY_CONFIG = configpaths.gajimpaths['MY_CONFIG']
    MY_CACHE = configpaths.gajimpaths['MY_CACHE']
    XTLS_CERTS = configpaths.gajimpaths['MY_PEER_CERTS']
    LOCAL_XTLS_CERTS = configpaths.gajimpaths['MY_CERT']

    PLUGINS_CONFIG_PATH = app.PLUGINS_CONFIG_DIR

    if not os.path.exists(MY_DATA):
        create_path(MY_DATA)
    elif os.path.isfile(MY_DATA):
        print(_('%s is a file but it should be a directory') % MY_DATA)
        print(_('Gajim will now exit'))
        sys.exit()

    if not os.path.exists(MY_CONFIG):
        create_path(MY_CONFIG)
    elif os.path.isfile(MY_CONFIG):
        print(_('%s is a file but it should be a directory') % MY_CONFIG)
        print(_('Gajim will now exit'))
        sys.exit()

    if not os.path.exists(MY_CACHE):
        create_path(MY_CACHE)
    elif os.path.isfile(MY_CACHE):
        print(_('%s is a file but it should be a directory') % MY_CACHE)
        print(_('Gajim will now exit'))
        sys.exit()

    if not os.path.exists(VCARD_PATH):
        create_path(VCARD_PATH)
    elif os.path.isfile(VCARD_PATH):
        print(_('%s is a file but it should be a directory') % VCARD_PATH)
        print(_('Gajim will now exit'))
        sys.exit()

    if not os.path.exists(AVATAR_PATH):
        create_path(AVATAR_PATH)
    elif os.path.isfile(AVATAR_PATH):
        print(_('%s is a file but it should be a directory') % AVATAR_PATH)
        print(_('Gajim will now exit'))
        sys.exit()

    if not os.path.exists(LOG_DB_FOLDER):
        create_path(LOG_DB_FOLDER)
    elif os.path.isfile(LOG_DB_FOLDER):
        print(_('%s is a file but it should be a directory') % LOG_DB_FOLDER)
        print(_('Gajim will now exit'))
        sys.exit()

    if not os.path.exists(PLUGINS_CONFIG_PATH):
        create_path(PLUGINS_CONFIG_PATH)
    elif os.path.isfile(PLUGINS_CONFIG_PATH):
        print(_('%s is a file but it should be a directory') % PLUGINS_CONFIG_PATH)
        print(_('Gajim will now exit'))
        sys.exit()

    if not os.path.exists(CACHE_DB_FOLDER):
        create_path(CACHE_DB_FOLDER)
    elif os.path.isfile(CACHE_DB_FOLDER):
        print(_('%s is a file but it should be a directory') % CACHE_DB_FOLDER)
        print(_('Gajim will now exit'))
        sys.exit()

    check_and_possibly_move_config()

    if not os.path.exists(LOG_DB_PATH):
        if os.path.exists(CACHE_DB_PATH):
            os.remove(CACHE_DB_PATH)
        create_log_db()
        app.logger.init_vars()
    elif os.path.isdir(LOG_DB_PATH):
        print(_('%s is a directory but should be a file') % LOG_DB_PATH)
        print(_('Gajim will now exit'))
        sys.exit()

    if not os.path.exists(CACHE_DB_PATH):
        create_cache_db()
        app.logger.attach_cache_database()
    elif os.path.isdir(CACHE_DB_PATH):
        print(_('%s is a directory but should be a file') % CACHE_DB_PATH)
        print(_('Gajim will now exit'))
        sys.exit()

    if not os.path.exists(XTLS_CERTS):
        create_path(XTLS_CERTS)
    if not os.path.exists(LOCAL_XTLS_CERTS):
        create_path(LOCAL_XTLS_CERTS)

def create_path(directory):
    head, tail = os.path.split(directory)
    if not os.path.exists(head):
        create_path(head)
    if os.path.exists(directory):
        return
    print(('creating %s directory') % directory)
    os.mkdir(directory, 0o700)
