#!/usr/bin/env python
# pylint: disable=invalid-name
# *****************************************************************************
# MLZ library of Tango servers
# Copyright (c) 2015-present by the authors, see LICENSE
#
# 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, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Module authors:
#   Alexander Lenz <alexander.lenz@frm2.tum.de>
#
# *****************************************************************************

"""Dump current server configuration in a RST table format."""

import argparse
import logging
import sys
from collections import OrderedDict
from pathlib import Path

# Add import path for inplace usage
sys.path.insert(0, str(Path(__file__).absolute().parents[1]))

# pylint: disable=wrong-import-position
from entangle.server import get_global_config
from entangle.server.config import read_resfile


class InfoAggregator:
    def __init__(self, resdir=None):
        self._resdir = resdir or get_global_config().resdir

    @property
    def servers(self):
        return sorted(entry.stem for entry in self._resdir.glob('*.res'))

    def get_devices(self, server):
        return sorted(self.get_resources(server))

    def get_resources(self, server):
        resfile = self._resdir / (server + '.res')
        return read_resfile(resfile, tango_format=False)[:2]

    def print_info(self, outformat):
        data = OrderedDict([
            (entry, self.get_resources(entry)) for entry in sorted(self.servers)
        ])

        srvlen, devlen, resnamelen, resvaluelen = self._calc_maxlengths(data)

        lines = self.formats[outformat](self, data, srvlen, devlen, resnamelen,
                                        resvaluelen)
        print('\n'.join(lines))

    def get_lines_dokuwiki(self, data, _srvlen, devlen, resnamelen, resvaluelen):
        lines = []

        # overall heading
        lines.append('=' * 5 + ' Entangle servers ' + '=' * 5)
        lines.append('')

        for srvname, (srvdesc, res) in data.items():
            # server heading
            lines.append('=' * 4 + ' ' + srvname + ' ' + '=' * 4)
            lines.append('')
            lines.append(srvdesc)
            lines.append('')
            lines.append('')

            header = '^ {:%i} ^ {:%i} ^ {:%i} ^' \
                     % (devlen, resnamelen, resvaluelen)
            devresline = '| {:%i} | {:%i} | {:%i} |' \
                         % (devlen, resnamelen, resvaluelen)
            # device table header
            lines.append(header.format('Device', 'Parameter', 'Value'))

            # device/param table
            for devname, devres in res.items():
                lines.append(devresline.format(devname, '',
                                               devres.get('description',
                                                          '').strip('\'')))

                for param, value in devres.items():
                    if param == 'description':
                        continue
                    # escape double slash if necessary (e.g. for iodevs)
                    value = repr(value).replace('//', '%%//%%')
                    lines.append(devresline.format('', param, value))

            lines.append('')
            lines.append('')

        return lines

    def get_lines_rst(self, data, _srvlen, devlen, resnamelen, resvaluelen):
        lines = []

        # overall heading
        heading = 'Entangle servers'
        lines.append('=' * len(heading))
        lines.append(heading)
        lines.append('=' * len(heading))
        lines.append('')

        for srvname, (srvdesc, res) in data.items():
            # server heading
            lines.append(srvname)
            lines.append('=' * len(srvname))
            lines.append('')
            lines.append(srvdesc)
            lines.append('')
            lines.append('')

            # device table header
            lines.append('=' * devlen + ' ' + '=' * resnamelen + ' ' + '='
                         * resvaluelen)

            devresline = '{:%i} {:%i} {:%i}' % (devlen, resnamelen, resvaluelen)
            lines.append(devresline.format('Device', 'Parameter', 'Value'))
            lines.append('=' * devlen + ' ' + '=' * resnamelen + ' ' + '='
                         * resvaluelen)

            # device/param table
            for devname, devres in res.items():
                lines.append(devresline.format(devname, '',
                                               devres.get('description',
                                                          '').strip('\'')))
                for param, value in devres.items():
                    if param == 'description':
                        continue
                    lines.append(devresline.format(
                        '\\', param, repr(value).replace('\\', '\\\\')))

            # device table footer
            lines.append('=' * devlen + ' ' + '=' * resnamelen + ' ' + '='
                         * resvaluelen)

            lines.append('')
            lines.append('')

        return lines

    def _calc_maxlengths(self, data):
        srvlen = max(len(srvname) for srvname in data)
        devlen = max(len(devname)
                     for srvdata in data.values()
                     for devname in srvdata[1])
        resnamelen = max(len(devname)
                         for srvdata in data.values()
                         for devdata in srvdata[1].values()
                         for devname in devdata)
        resvaluelen = 30
        return srvlen, devlen, resnamelen, resvaluelen

    formats = {
        'rst': get_lines_rst,
        'dokuwiki': get_lines_dokuwiki,
    }


def parse_args(argv):
    parser = argparse.ArgumentParser(description='Print entangle server '
                                     'information')
    parser.add_argument('-v', '--verbose', action='store_true',
                        help='Verbose logging', default=False)
    parser.add_argument('-f', '--format', type=str,
                        choices=list(InfoAggregator.formats),
                        help='Select the output format', default='rst')
    parser.add_argument('-r', '--resdir', action='store', type=Path,
                        help='Use a different resource file directory')
    return parser.parse_args(argv[1:])


def main(argv):
    args = parse_args(argv)

    loglevel = logging.DEBUG if args.verbose else logging.INFO
    logging.basicConfig(level=loglevel, format='%(message)s')

    info = InfoAggregator(args.resdir)
    info.print_info(args.format)


if __name__ == '__main__':
    sys.exit(main(sys.argv))
