#!/usr/libexec/platform-python

# Copyright (C) 2011 Oracle. 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, version 2.  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, write to the Free
# Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 021110-1307, USA.

import glob
import os
import optparse
import re
import sys

from templateconfig.common import (error, get_target_path, get_script_path,
         get_script_dir, get_priority, check_priority, TARGETS)


def get_meta(name):
    result = {}
    info_begin_re = re.compile(r"^### BEGIN PLUGIN INFO\s*$")
    info_end_re = re.compile(r"^### END PLUGIN INFO\s*$")
    info_line_re = re.compile(r"^# (?P<key>[^\s:]+):\s*(?P<value>.*\S)\s*$")
    info_line_cont_re = re.compile(r"^#(\t|  )\s*(?P<cont>.*)$")
    try:
        script = open(get_script_path(name))
        key = None
        value = None
        info_begin = False
        for line in script:
            if not line.startswith("#"):
                if not info_begin:
                    continue
                else:
                    raise Exception('syntax error: %s' % line)
            if info_begin_re.match(line):
                info_begin = True
                continue
            if not info_begin:
                continue
            if info_end_re.match(line):
                break
            info_line_match = info_line_re.match(line)
            if info_line_match:
                key = info_line_match.group("key")
                value = info_line_match.group("value")
                result[key] = value
                continue
            info_line_cont_match = info_line_cont_re.match(line)
            if info_line_cont_match:
                value = " ".join((value, info_line_cont_match.group("cont")))
                if key not in result:
                    raise Exception('syntax error: %s' % line)
                result[key] = value
        return result
    except Exception as err:
        error('cannot get required meta data from %s: %s', name, err)


def get_config(name):
    result = []
    if not os.path.isfile(get_script_path(name)):
        error('unknown script: %s', name)
    result.append(name)
    for target in TARGETS:
        links = glob.glob('%s/??%s' % (get_target_path(target), name))
        if len(links) == 0:
            result.append('off')
        elif len(links) == 1:
            priority = get_priority(links[0])
            result.append('on:%s' % priority)
        else:
            error('multiple links found for %s under %s', name, target)
    return result


def unlink_script(name, target):
    try:
        for lnk in glob.glob('%s/??%s' % (get_target_path(target), name)):
            os.unlink(lnk)
    except Exception as err:
        error('cannot unlink script %s: %s', name, err)


def link_script(name, target, priority):
    check_priority(priority)
    unlink_script(name, target)
    dest = '%s/%s%s' % (get_target_path(target), priority, name)
    try:
        os.symlink(get_script_path(name), dest)
    except Exception as err:
        error('cannot symlink script %s to %s: %s', name, dest, err)


def print_line(name, config):
    print(('%-20s' % name), end=' ')
    for item in config:
        print(('%-11s' % item), end=' ')
    print()


def print_header():
    print_line('name', TARGETS)


def print_config(config):
    print_line(config[0], config[1:])


def do_list(name=None):
    result = []
    if name:
        result.append(get_config(name))
    else:
        for name in os.listdir(get_script_dir()):
            result.append(get_config(name))
    if result:
        print_header()
        for item in sorted(result):
            print_config(item)


def add(name):
    meta = get_meta(name)
    for target in TARGETS:
        if target not in meta:
            continue
        priority = meta[target]
        link_script(name, target, priority)


def delete(name):
    for target in TARGETS:
        unlink_script(name, target)


def set_target(targets, name, value):
    if value not in ['on', 'off']:
        error('unknown value: %s, should be <on|off>', value)
    meta = get_meta(name)
    for target in targets.split(','):
        target = target.strip()
        if target not in TARGETS:
            error('unknown target: %s', target)
        if value == 'on':
            if target not in meta:
                error('cannot get priority of target %s for %s', target, name)
            priority = meta[target]
            link_script(name, target, priority)
        else:
            unlink_script(name, target)


def main():
    usage = ('%prog [option] ...\n\n'
             'examples:\n'
             '  %prog --list [name]\n'
             '  %prog --add name\n'
             '  %prog --del name\n'
             '  %prog --target <targets> name <on|off>')
    parser = optparse.OptionParser(usage)
    parser.add_option('', '--list', action='store_true',
                      help='list script status')
    parser.add_option('', '--add', action='store_true',
                      help='add new script')
    parser.add_option('', '--del', action='store_true', dest='delete',
                      help='delete script')
    parser.add_option('', '--target', action='store',
                      help=('specify the targets, separated by comma, '
                            'e.g.: "configure,unconfigure"'))
    (opts, args) = parser.parse_args()

    def show_usage():
        parser.print_help(sys.stderr)
        sys.exit(1)

    if opts.list:
        if len(args) == 0:
            do_list()
        elif len(args) == 1:
            do_list(args[0])
        else:
            show_usage()
    elif opts.add:
        if len(args) == 1:
            add(args[0])
        else:
            show_usage()
    elif opts.delete:
        if len(args) == 1:
            delete(args[0])
        else:
            show_usage()
    elif opts.target:
        if len(args) == 2:
            set_target(opts.target, args[0], args[1])
        else:
            show_usage()
    else:
        show_usage()


if __name__ == '__main__':
    main()
