#!/usr/bin/python2

from __future__ import print_function
import sys
import argparse
import subprocess

import perfact.generic
import perfact.dbconn


def backup():
    """Backup translation tables
    """
    perfact.dbconn.dbconn.execute("""
        drop table if exists i18nelem_backup;
        drop table if exists i18ntrans_backup;
        select * into i18ntrans_backup from i18ntrans;
        select * into i18nelem_backup from i18nelem;
    """)


def cleanup():
    """Remove elements that have no non-trivial translations.
    """
    perfact.dbconn.dbconn.execute("""
        drop table if exists i18ntrans_merge;
        drop table if exists i18nelem_merge;

        -- todo: if there are multiple languages and one of them is trivially
        -- translated and the other is non-trivially translated
        delete from i18nelem where i18nelem_id in (
          -- check for absence of non-trivial translations
          select i18nelem_id
          from i18nelem
          left join i18ntrans
            on i18ntrans_i18nelem_id = i18nelem_id
           and (i18ntrans_lang <> i18n_default_lang()
               or i18ntrans_text <> i18nelem_text)
           and coalesce(i18ntrans_text,'') <> ''
          where i18ntrans_id is null
        );
    """)


def dump(f):
    """Clean up translation tables, create copies of them and dump the copies
    into file f.
    """
    backup()
    cleanup()
    perfact.dbconn.dbconn.execute("""
        select * into i18ntrans_merge from i18ntrans;
        select * into i18nelem_merge from i18nelem;
        alter table i18nelem_merge add primary key (i18nelem_id);
        alter table i18ntrans_merge add constraint i18nelem_id
          foreign key (i18ntrans_i18nelem_id)
          references i18nelem_merge (i18nelem_id)
          on update cascade on delete cascade;
    """)
    perfact.dbconn.dbconn.commit()
    subprocess.Popen(
        [
            '/usr/bin/pg_dump',
            'perfactema', '-U', 'zope',
            '-t', 'i18ntrans_merge',
            '-t', 'i18nelem_merge',
        ],
        stdout=f
    ).wait()
    cleanup()


def restore(f):
    backup()
    cleanup()
    perfact.dbconn.dbconn.commit()
    subprocess.Popen(
        [
            '/usr/bin/psql', 'perfactema', 'zope', '--echo-queries'
        ],
        stdin=f
    ).wait()
    perfact.dbconn.dbconn.execute("""\
-- Remove entries already present
delete from i18nelem_merge where i18nelem_id in (
    select m.i18nelem_id
      from i18nelem_merge m
      join i18nelem o
        on o.i18nelem_domain is not distinct from m.i18nelem_domain
       and o.i18nelem_context is not distinct from m.i18nelem_context
       and o.i18nelem_attr is not distinct from m.i18nelem_attr
       and o.i18nelem_text is not distinct from m.i18nelem_text
);

-- Renumber translation entries using the target sequence
update i18ntrans_merge set i18ntrans_id = nextval('i18ntrans_s');

-- Renumber elements twice - this cascades to i18ntrans_i18nelem_id
select greatest(
    (select max(i18nelem_id) from i18nelem_merge) , -- for first renumbering
    (
        (select last_value from i18nelem_s)
        + (select count(*) from i18nelem_merge)
    ) -- for second renumbering
) + 1000 -- in case someone creates entries in the mean time
    """)
    # it seems it is not possible to feed the result of a query directly into
    # the start parameter of create sequence
    start_index = perfact.dbconn.dbconn.tuples()[0][0]
    perfact.dbconn.dbconn.execute("""
create sequence i18nelem_merge_s start %d;
update i18nelem_merge set i18nelem_id = nextval('i18nelem_merge_s');
drop sequence i18nelem_merge_s;

update i18nelem_merge set i18nelem_id = nextval('i18nelem_s');

-- Insert them
insert into i18nelem select * from i18nelem_merge;
select setval('i18nelem_s', (select max(i18nelem_id) from i18nelem));
insert into i18ntrans select * from i18ntrans_merge;
    """ % start_index)
    cleanup()


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='Transfer translation tables between systems',
            epilog="""
EXAMPLES:

  perfact-mergetranslations -o > dump.sql
    Create tables i18nelem_merge and i18ntrans_merge on local system and dump
    them into file.

  perfact-mergetranslations -i < dump.sql
    Merge contents from file into database.

  perfact-mergetranslations --fetch
    Fetch translations from source-system and merge them into local system.

  perfact-mergetranslations --push
    Obtain local translations, push them to source-system and merge them there.

            """,
            formatter_class=argparse.RawDescriptionHelpFormatter,
            )
    group = parser.add_mutually_exclusive_group()

    group.add_argument(
        '--output', '-o',
        action='store_true', default=False,
        help='Dump translation tables to stdout.',
    )
    group.add_argument(
        '--input', '-i',
        action='store_true', default=False,
        help='Read translation tables from stdin.',
    )
    group.add_argument(
        '--fetch',
        action='store_true', default=False,
        help='Fetch translations from source-system'
    )
    group.add_argument(
        '--push',
        action='store_true', default=False,
        help='Push translations to source-system'
    )
    args = parser.parse_args()

    if args.output:
        dump(sys.stdout)
    elif args.input:
        restore(sys.stdin)
    elif args.fetch:
        proc = subprocess.Popen(
            [
                '/usr/bin/ssh', 'source-system',
                'perfact-mergetranslations -o'
            ],
            stdout=subprocess.PIPE
        )
        restore(proc.stdout)
        proc.wait()
    elif args.push:
        proc = subprocess.Popen(
            [
                '/usr/bin/ssh', 'source-system',
                'perfact-mergetranslations -i'
            ],
            stdin=subprocess.PIPE,
        )
        dump(proc.stdin)
        proc.wait()
