#!/bin/env python
# ptsReadme.py
#
#    ========== licence begin  GPL
#    Copyright (C) 2001 SAP AG
#
#    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.
#    ========== licence end
#

import sys
import string
import os

import sql.sapdb

def getDescriptionPatches ():
    fname = os.path.join (os.environ ['TOOL'], 'data', 'relinfo.patch')
    locals = {}
    execfile (fname, locals)
    return locals ['idsToIgnore'], locals ['idsToPatch']

def patchDescription (patchDict, id, description):
    patches = patchDict.get (id)
    if patches:
        for search, replace in patches:
            description = string.replace (description, search, replace, 1)
    return description

def getColNames (cursor):
    result = []
    for info in cursor.getDescription ():
        result.append (info [0])
    return result

def dumpCursor (cursor):
    print string.join (getColNames (cursor), '|')
    for row in cursor:
        print string.join (map (str, row), '|')

def normalizeReleaseString (str):
    numbers = tuple (map (int, string.split (str, '.')))
    if len (numbers) == 4:
        result = '%d%d.%02d.%02d' % numbers
    elif len (numbers) == 3:
        result = '%02d.%02d.%02d' % numbers
    else:
        raise 'Invalid release string', str
    return result

def formatReleaseString (str):
    version, cl, pl = map (int, string.split (str, '.'))
    major = version / 10
    minor = version % 10
    return '%d.%d.%02d.%02d' % (major, minor, cl, pl)

def wordWrapLine (line, maxline = 60):
    result = []
    restline = line
    while len (restline) > maxline:
        # find space in first maxline chars
        spacePos = string.rfind (restline [:maxline], ' ')
        if spacePos == -1:
            # find space in whole restline
            spacePos = string.find (restline, ' ', maxline)
        if spacePos == -1:
            # use whole restline
            spacePos = len (restline)
        result.append (restline [:spacePos])
        restline = restline [spacePos + 1:]
    if restline:
        result.append (restline)
    return result

def wordWrapLines (lines, maxline = 60):
    result = []
    for line in lines:
        result.extend (wordWrapLine (line, maxline))
    return result

_componentsToIgnore = [
    'Description',
    'Development Environment',
    'JTest',
    'JTestFrame',
    'MUT',
    'PTS',
    'R3Setup',
    'XDIAGNOSE',
    'XPU',
    'XWIZARD',
]

_components = [
    "Kernel",
    "System Tables",
    "Setup",
    "Installation",
    "C Precompiler",
    "Precompiler Runtime",
    "JDBC",
    "ODBC",
    "Scripting",
    "DBMClient",
    "DBMGUI",
    "DBMServer",
    "DB Analyzer",
    "Loader",
    "SQL Studio",
    "SQLFilter",
    "WWW Server",
    "Web DBM",
    "Web SQL",
    "WebAgent",
    "WebDAV",
    # "Web PTS",
    "Runtime Environment",
    "XSERVER",
]

def singleQuote (str):
    return "'" + str + "'"


def list2SQL (list):
    quoted = map (singleQuote, list)
    return string.join (quoted, ', ')

_descKindMapping = [
    "Fixed the following bug",
    "Bug fixed",
    "New Feature",
]

_baseDescription = 0
_bugDescription = 1
_featureDescription = 2
_cutoffRelease = '73.00.18'

def ptsReadme (session, outstream, options):
    fromString = normalizeReleaseString (options.fromString)
    toString = normalizeReleaseString (options.toString)
    write = outstream.write
    outstream.write ('\nSAP DB Release Information (%s to %s)\n\n' % (
        formatReleaseString (fromString),
        formatReleaseString (toString)))
    targetString = "substr (\"TargetVersion\", 1, 2) || '.' || substr (\"TargetCL\", 1, 2) || '.' || substr (\"TargetPL\", 1, 2)"
    cmd = """select \"ErrorID\", %(targetString)s
        FROM PTS.\"ErrorView\"
        WHERE '%(fromString)s' <= %(targetString)s AND %(targetString)s <= '%(toString)s'
        AND   \"Status\" = '4'
        AND \"ComponentName\" = ?
        ORDER BY 2 DESC, 1 DESC
        """ % locals ()
    prepared = session.prepare (cmd)
    for compname in _components:
        print compname
        componentCursor = prepared.execute ([compname])
        #fetchDescription = session.prepare ('select first "DESCRIPTIONTYPE", "Description" into ?, ? '
        #    + ' from PTS."Descriptions" where "ErrorID" = ? order by "DESCRIPTIONTYPE"').execute
        fetchDescription = session.prepare ('select "DESCRIPTIONTYPE", "Description"'
            + ' from PTS."Descriptions" where "ErrorID" = ? order by "DESCRIPTIONTYPE" DESC').execute
        toIgnore, toPatch = getDescriptionPatches ()
        introWritten = None
        for row in componentCursor:
            id, release = row
            if id in toIgnore:
                continue
            cursor = fetchDescription ([id])
            (kind, description) = cursor.next ()
            del cursor
            if (kind == _baseDescription) and (release >= _cutoffRelease):
                continue
            if not introWritten:
                outstream.write ('\n' + compname + ':\n')
                outstream.write (('=' * len (compname)) + '=\n\n')
                introWritten = 1
            outstream.write ('    PTS: %s    since: %s\n\n' % (id, formatReleaseString (release)))
            description = patchDescription (toPatch, id, description)
            lines = string.split (description, '\xd\n')
            outstream.write ('    ' + _descKindMapping [kind] + ':\n')
            for line in wordWrapLines (lines):
                line = string.rstrip (line)
                if line:
                    write ('        ' + line + '\n')
            write ('\n\n')



def main (options, args):
    """generates a release info

    call as: ptsReadme.py -from 72.05.01 -to 72.06.30
    """
    if options.outfile:
        outstream = open (options.outfile, 'wt')
    else:
        outstream = sys.stdout
    username, pwd = string.split (options.userInfo, ',')
    session = sql.sapdb.connect (string.upper (username), pwd, 'PTS', 'pgwdf160')
    ptsReadme (session, outstream, options)

def _options ():
    return [
        # (optstring, varname, typechar, default, help)
        ('u', 'userInfo', ':', 'PTSALLREAD,PTSALLREAD', 'user info (name,pwd)'),
        ('o', 'outfile', ':', None, 'output file'),
        ('from', 'fromString', ':', None, 'from CL (release.CL.PL)'),
        ('to', 'toString', ':', None, 'to CL (release.CL.PL)'),
        ]

if __name__ == '__main__':
    import optlib
    optlib.optMain2 (main, _options ())
