#!/bin/sh
# Tcl ignores the next line -*- tcl -*- \
exec tclsh8.6 "$0" -- "$@"

######################################################################
#                ProjMan 2
#        Distributed under GNU Public License
# Author: Sergey Kalinin svk@nuk-svk.ru
# Copyright (c) "SVK", 2024, https://nuk-svk.ru
#######################################################################
# Changelog generator from the Git commit history.
# For DEB and RPM packages
# usage a git command:
# 
#    git log --abbrev-commit --all --pretty='%h, %ad, %an, %ae, %s, %b'
#######################################################################

# puts $tcl_platform(platform)

# Устанавливаем рабочий каталог, если его нет то создаём.
# Согласно спецификации XDG проверяем наличие переменных и каталогов
if [info exists env(XDG_CONFIG_HOME)] {
    set dir(cfg) [file join $env(XDG_CONFIG_HOME) changelog-gen]
} elseif [file exists [file join $env(HOME) .config]] {
    set dir(cfg) [file join $env(HOME) .config changelog-gen]
} else {
    #set dir(cfg) [file join $env(HOME) .changelog-gen]
}

if {[file exists $dir(cfg)] == 0} {
    file mkdir $dir(cfg)
}

# Use whereis command for finding the git executable file.
# for unix-like operating systems
proc GetGitCommandUnix {} {
    global gitCommand
    set cmd "whereis -b git"
    catch "exec $cmd" result
    # puts $result
    if {$result ne ""} {
        set fields [split $result ":"]
        # puts $fields
        if {[lindex $fields 1] ne ""} {
            # puts [lindex $fields 1]
	        set gitCommand "[string trim [lindex $fields 1]]"
		} else {
            puts "GIT command not found"
            exit
        }
    }
}

# Setting the git-command for windows family OS
proc GetGitCommandWindows {} {
    global gitCommand
    set gitCommand "c:/git/bin/git.exe"
}

switch $tcl_platform(platform) {
    unix     {GetGitCommandUnix}
    windows  {GetGitCommandWindows}
}

proc ReadGitLog {} {
    global args gitCommand lastCommitTimeStampSec
    set cmd exec
    set i 0
    lappend cmd "$gitCommand"
    lappend cmd "log"
    lappend cmd "--abbrev-commit"
    # Проверяем была ли запись для данного проекта если была то к времени последнего коммита прибавляем 1 сек.
    # и получаем журнал после этой даты
    if {[info exists lastCommitTimeStampSec] && [info exists args(--last)]} {
        lappend cmd "--after='[clock format [clock add $lastCommitTimeStampSec 1 second] -format {%a, %e %b %Y %H:%M:%S %z}]'"
    }
    lappend cmd "--all"
    lappend cmd "--pretty='%h, %ad, %an, %ae, %s, %b'"
    # puts $cmd
    catch $cmd pipe
    # puts $pipe
    set outBuffer ""
    foreach line [split $pipe "\n"] {
        # puts $line
        # set line [string trim $line]
        set line [string trim [string trim $line] {'}] 
        if {[regexp -nocase -all -- {^[0-9a-z]+} $line match]} {
            set outBuffer $line
            if {$outBuffer ne ""} {
                lappend res [list $i $outBuffer]
                incr i
            }
            # puts $outBuffer
        } else {
            if {$line ne ""} {
                append outBuffer ". " $line
            }
        }
    }
    # puts $res
    if [info exists res] {
        return $res
    } else {
        puts "\nRepository '$args(--project-name)' do not have any changes\n"
        exit
    }
}

proc StoreProjectInfo {timeStamp} {
    global dir args
    set cfgFile [open [file join $dir(cfg) $args(--project-name).conf]  "w+"]
    puts $cfgFile "# set args(--project-version) \"$args(--project-version)\""
    puts $cfgFile "# set args(--project-release) \"$args(--project-release)\""
    puts $cfgFile "set lastCommitTimeStamp \"$timeStamp\""
    puts $cfgFile "set lastCommitTimeStampSec [clock scan $timeStamp]"
    close $cfgFile   
}


proc GenerateChangelogDEB {} {
    global args
    # puts "GenerateChangelogDEB"
    set lastCommitTimeStamp ""
    set commiter ""
    set commitText ""
    # ReadGitLog
    set lst [lsort -integer -index 0 [ReadGitLog]]
    # puts $lst
    # exit
    set outText ""
    foreach l $lst {
        set index [lindex $l 0]
        set line [lindex $l 1]
        # puts "$index - $line"
        set record [split $line ","]
        set timeStamp [string trim [lindex $record 1]]
        set email [string trim [lindex $record 3]]
        if {$lastCommitTimeStamp eq ""} {
            set lastCommitTimeStamp [string trim [lindex $record 1]]
        }
        set timeStamp [clock format [clock scan $timeStamp] -format {%a, %e %b %Y %H:%M:%S %z}]
        # puts "> $commiter"
        if {$index == 0} {
            puts "$args(--project-name) ($args(--project-version)-$args(--project-release)) stable; urgency=medium\n"
            append outText "$args(--project-name) ($args(--project-version)-$args(--project-release)) stable; urgency=medium\n\n"
            set commiter [lindex $record 2]
            StoreProjectInfo $timeStamp
         	  # puts "\n \[ [string trim $commiter] \]"
        }
        # puts ">> $commiter"
        if {$commiter ne [lindex $record 2]} {
            puts "\n -- [string trim $commiter] <$email>  $timeStamp"
            append outText "\n -- [string trim $commiter] <$email>  $timeStamp\n"
            puts "\n$args(--project-name) ($args(--project-version)-$args(--project-release)) stable; urgency=medium\n"
            append outText "\n$args(--project-name) ($args(--project-version)-$args(--project-release)) stable; urgency=medium\n\n"
            set commiter [lindex $record 2]
            # puts "\n \[ [string trim $commiter] \]"
        }
        
        set commitTex [lindex $record 4]
        puts "  * $commitTex"
        append outText "  * $commitTex\n"

    }
    puts "\n -- [string trim $commiter] <$email>  $timeStamp"
    append outText "\n -- [string trim $commiter] <$email>  $timeStamp\n"
    return $outText
}

proc GenerateChangelogRPM {} {
    puts "GenerateChangelogRPM"
    
}

proc GenerateChangelogTXT {} {
    global args
    set lastCommitTimeStamp ""
    set commiter ""
    set commitText ""
    set lst [lsort -integer -index 0 [ReadGitLog]]
    puts "$args(--project-name) ($args(--project-version)-$args(--project-release)"
    foreach l $lst {
        set index [lindex $l 0]
        set line [lindex $l 1]
        # puts "$index - $line"
        set record [split $line ","]
        set timeStamp [string trim [lindex $record 1]]
        set email [string trim [lindex $record 3]]
        if {$lastCommitTimeStamp eq ""} {
            set lastCommitTimeStamp [string trim [lindex $record 1]]
        }
        set timeStamp [clock format [clock scan $timeStamp] -format {%a, %e %b %Y %H:%M:%S %z}]
        # puts "> $commiter"
        if {$index == 0} {
            append outText "$args(--project-name) ($args(--project-version)-$args(--project-release))\n"
            set commiter [lindex $record 2]
            puts "\n[string trim $commiter] <$email>  $timeStamp"
            append outText "\n[string trim $commiter] <$email>  $timeStamp\n"
            StoreProjectInfo $timeStamp
        }
        if {$commiter ne [lindex $record 2]} {
            puts "\n[string trim $commiter] <$email>  $timeStamp"
            append outText "\n[string trim $commiter] <$email>  $timeStamp\n"
            set commiter [lindex $record 2]
        }
        
        set commitTex [lindex $record 4]
        puts "  - $commitTex"
        append outText "  - $commitTex\n"

    }
    return $outText
}
# puts [ReadGitLog]

proc ShowHelp {} {
    puts "\nChangelog generator from the Git commit history. For DEB and RPM packages"
    puts "Usage:\n"
    puts "\tchangelog-gen \[options\]\n"
    puts "Where options:"
    puts "\t--project-name - name of project (package) "
    puts "\t--project-version - package version"
    puts "\t--project-release - package release name (number)"
    puts "\t--deb - debian package format of changelog"
    puts "\t--rpm - rpm package format of changelog"
    puts "\t--txt - plain text changelog out"
    puts "\t--out-file - changelog file name"
    puts "\t--last - The timestamp since the last launch of this program for a given project"
}

proc StoreChangeLog {outText} {
    global args
    if [file exists $args(--out-file)] {
        file copy -force $args(--out-file) "$args(--out-file).tmp"
        
        set origOutFile [open "$args(--out-file).tmp"  "r"]
        set origText [read $origOutFile]
        close $origOutFile
        
        set outFile [open $args(--out-file)  "w"]
        puts $outFile $outText
        puts $outFile $origText
        close $outFile
        
        if [info exists args(--last)] {
            set outFile [open $args(--out-file)  "r+"]
            puts $outFile $outText
            close $outFile
        } else {
            set outFile [open $args(--out-file)  "w+"]
            puts $outFile $outText
            close $outFile
        }
    } else {
        set outFile [open $args(--out-file)  "w+"]
        puts $outFile $outText
        close $outFile
    }
}

set arglen [llength $argv]
set index 0
while {$index < $arglen} {
    set arg [lindex $argv $index]
    switch -exact $arg {
        --project-name {
            set args($arg) [lindex $argv [incr index]]
        }
        --project-version {
            set args($arg) [lindex $argv [incr index]]
        }
        --project-release {
            set args($arg) [lindex $argv [incr index]]
        }
        --deb {
            set args($arg) true
        }
        --rpm {
            set args($arg) true
        }
        --txt {
            set args($arg) true
        }
        --out-file {
            set args($arg) [lindex $argv [incr index]]
        }
        --last {
            set args($arg) true
        }
        --help {
            ShowHelp
            exit
        }
        default  {
            set filename [lindex $argv $index]
        }
    }
    incr index
}

if ![info exists args(--project-name)] {
    puts "You mast set --project-name option\n"
    exit
}
if ![info exists args(--project-version)] {
    puts "You mast set --project-version option\n"
    exit
}
if ![info exists args(--project-release)] {
    puts "You mast set --project-release option\n"
    exit
}

if [file exists [file join $dir(cfg) $args(--project-name).conf]] {
    source [file join $dir(cfg) $args(--project-name).conf]
}

foreach arg [array names args] {
    puts "$arg $args($arg)"
}

if [info exists args(--deb)] {
    set outText [GenerateChangelogDEB]
    if [info exists args(--out-file)] {
        StoreChangeLog $outText
    }
}
if [info exists args(--rpm)] {
    GenerateChangelogRPM
}
if [info exists args(--txt)] {
    set outText [GenerateChangelogTXT]
    if [info exists args(--out-file)] {
        StoreChangeLog $outText
    }
}
