#!/usr/bin/env python

# THIS FILE IS PART OF THE CYLC SUITE ENGINE.
# Copyright (C) 2008-2016 NIWA
#
# 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 3 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/>.

"""cylc [db] copy|cp [OPTIONS] REG REG2 TOPDIR

Copy suite or group REG to TOPDIR, and register the copy as REG2.

Consider the following three suites:

% cylc db print '^foo'     # printed in flat form
foo.bag     | "Test Suite Zero" | /home/bob/zero
foo.bar.qux | "Test Suite Two"  | /home/bob/two
foo.bar.baz | "Test Suite One"  | /home/bob/one

% cylc db print -t '^foo'  # printed in tree from
foo
 |-bag    "Test Suite Zero" | /home/bob/zero
 `-bar
   |-baz  "Test Suite One"  | /home/bob/one
   `-qux  "Test Suite Two"  | /home/bob/two

These suites are stored in a flat directory structure under /home/bob,
but they are organised in the suite database as a group 'foo' that
contains the suite 'foo.bag' and a group 'foo.bar', which in turn
contains the suites 'foo.bar.baz' and 'foo.bar.qux'.

When you copy suites with this command, the target registration names
are determined by TARGET and the name structure underneath SOURCE, and
the suite definition directories are copied into a directory tree under
TOPDIR whose structure reflects the target registration names. If this
is not what you want, you can copy suite definition directories manually
and then register the copied directories manually with 'cylc register'.

EXAMPLES (using the three suites above):

% cylc db copy foo.bar.baz red /home/bob       # suite to suite
  Copying suite definition for red
% cylc db print "^red"
  red | "Test Suite One" | /home/bob/red

% cylc copy foo.bar.baz blue.green /home/bob   # suite to group
  Copying suite definition for blue.green
% cylc db pr "^blue"
  blue.green | "Test Suite One" | /home/bob/blue/green

% cylc copy foo.bar orange /home/bob           # group to group
  Copying suite definition for orange.qux
  Copying suite definition for orange.baz
% cylc db pr "^orange"
  orange.qux | "Test Suite Two" | /home/bob/orange/qux
  orange.baz | "Test Suite One" | /home/bob/orange/baz"""

import sys
from cylc.remote import remrun
if remrun().execute():
    sys.exit(0)

import os
import re
import shutil

import cylc.flags
from cylc.option_parsers import CylcOptionParser as COP
from cylc.mkdir_p import mkdir_p
from cylc.registration import RegistrationDB, RegistrationError
from cylc.regpath import RegPath


def main():
    parser = COP(__doc__,
                 argdoc=[("REG", "Source suite name"),
                         ("REG2", "Target suite name"),
                         ("TOPDIR", "Top level target directory.")])

    parser.add_option(
        "--db-from",
        help="Copy suites from another DB (defaults to --db).",
        metavar='PATH', action="store", default=None, dest="dbfrom")

    (options, args) = parser.parse_args()
    arg_from = args[0]
    arg_to = args[1]
    arg_dir = args[2]

    if options.dbfrom:
        dbfrom = RegistrationDB(options.dbfrom)
    else:
        dbfrom = RegistrationDB(options.db)
    db = RegistrationDB(options.db)

    flist = dbfrom.get_list('^' + arg_from + r'\b')
    if len(flist) == 0:
        sys.exit('ERROR, no suites matched: ' + arg_from)

    for item in flist:
        freg, fdir, ftitle = item
        treg = re.sub(r'\b' + arg_from + r'\b', arg_to, freg)

        tdir = RegPath(treg).get_fpath()
        tdir = os.path.join(arg_dir, tdir)

        tdir = os.path.abspath(tdir)
        mkdir_p(os.path.dirname(tdir))

        print 'COPY', fdir, '\n  TO', tdir
        shutil.copytree(fdir, tdir)
        db.register(treg, tdir)


if __name__ == "__main__":
    try:
        main()
    except Exception as exc:
        if cylc.flags.debug:
            raise
        sys.exit(str(exc))
