require_relative 'sisu_version'
module Project_details
  include SiSUversion
  def self.name
    'SiSU'
  end
  def self.summary
    'documents - structuring, publishing in multiple formats & search'
  end
  def self.description
    'documents - structuring, publishing in multiple formats & search'
  end
  def self.homepage
    'http://www.sisudoc.org'
  end
  def self.thor
    "ruby-thor files for the installation/setup of #{name}"
  end
  def self.platform_notice
    "[#{name} is for Linux/Unix Platforms]"
  end
  def self.env
    RbConfig::CONFIG
  end
  def self.host
    env['host']
  end
  def self.dir
    def self.proj
      Project_details.name.downcase
    end
    def self.arch
      env['archdir']
    end
    def self.sitearch
      env['sitearchdir']
    end
    def self.bin
      env['bindir']
    end
    def self.lib
      env['sitelibdir']
    end
    def self.data
      env['datadir']
    end
    def self.share
      "#{env['datadir']}/sisu"
    end
    def self.conf
      env['sysconfdir']
    end
    def self.man
      env['mandir']
    end
    def self.vim
      "#{env['datadir']}/sisu/vim"
    end
    def self.out
      "#{env['localstatedir']}/#{proj}"
    end
    def self.rubylib
      env['LIBRUBYARG_SHARED']
    end
    def self.pwd
      Dir.pwd #ENV['PWD']
    end
    self
  end
  def self.version
    stamp={}
    v="#{dir.pwd}/data/sisu/version.yml"
    if File.exist?(v)
      stamp=YAML::load(File::open(v))
      stamp[:version]
    else ''
    end
  end
  def self.system_info
    ##{Project_details.platform_notice}
    puts <<-WOK
  Host
    host:             #{Project_details.host}
    arch:             #{Project_details.dir.arch}
    sitearch:         #{Project_details.dir.sitearch}
  Directories for installation
    bin:                                          #{Project_details.dir.bin}
    lib (site-ruby):                              #{Project_details.dir.lib}/#{Project_details.dir.proj}/v*
    conf [etc]:                                   #{Project_details.dir.conf}/#{Project_details.dir.proj}
    data (odf, shared images):                    #{Project_details.dir.share}
    vim  (vim syntax, highlighting, ftplugin):    #{Project_details.dir.data}/sisu/vim
    data (README, version_manifest):              #{Project_details.dir.data}/doc/#{Project_details.dir.proj}
    man (manual pages):                           #{Project_details.dir.man}
    output:                                       #{Project_details.dir.out}
      processing:                                 #{Project_details.dir.out}/processing
      www:                                        #{Project_details.dir.out}/www
    rubylib:                                      #{Project_details.dir.rubylib}

    WOK
  end
  def self.gem_env
    system("gem env")
  end
end
module Utils
  def self.answer?(ask)
    resp='redo'
    print ask + " ['yes', 'no' or 'quit']: "
    resp=File.new('/dev/tty').gets.strip #resp=gets.strip
    if    resp == 'yes'        then true
    elsif resp == 'no'         then false
    elsif resp =~/^quit|exit$/ then exit
    else                       puts "[please type: 'yes', 'no' or 'quit']"
                               answer?(ask)
    end
  end
  def self.default_notice # local help not implemented description incorrect
    ans= %{#{Project_details.thor}
    Information on alternative actions is available using:
    [if ruby-thor is installed:]
      "#{$called_as} help")
    Default action selected - "install #{Project_details.name}" proceed? }
    resp=answer?(ans)
    exit unless resp
  end
  def self.chmod_file(place)
    if place =~/\/bin/; File.chmod(0755,place)
    else                File.chmod(0644,place)
    end
  end
  def self.chmod_util(place)
    if place =~/\/bin/; chmod(0755,place)
    else                chmod(0644,place)
    end
  end
  def self.system_date
    `date "+%Y-%m-%d"`.strip
  end
  def self.system_date_stamp
    `date "+%Yw%W/%u"`.strip
  end
  def self.program_found?(prog)
    found=`which #{prog}` #`whereis #{make}`
    (found =~/bin\/#{prog}\b/) ? :true : :false
  end
end
module Install
                                                           #%% using a directory and its mapping
  def self.setup_find_create(dir_get,dir_put,exclude_files=['\*'],act)               #primary,
    begin
      Find.find("#{Project_details.dir.pwd}/#{dir_get}") do |f|
        stub=f.scan(/#{Project_details.dir.pwd}\/#{dir_get}\/(\S+)/).join
        place="#{dir_put}/#{stub}"
        action=case
        when File.file?(f)
          unless f =~/#{exclude_files.join("|")}/
            unless act==:dryrun
              cp(f,place)
              Utils.chmod_file(place)
            end
            "->  #{dir_put}/"
          end
        when File.directory?(f)
          if not FileTest.directory?(place) \
          and not act==:dryrun
            FileUtils.mkpath(place)
          end
          "./#{dir_get}/"
        else '?'
        end
        puts "#{action}#{stub}"
      end
    rescue
      puts "\n\n[ are you root? required for install ]"
    end
  end
  def self.setup_find_cp_r(dir_get,dir_put,act)                                    #secondary, using recursive copy
    begin
      Find.find("#{Project_details.dir.pwd}/#{dir_get}") do |f|
        stub=f.scan(/#{Project_details.dir.pwd}\/#{dir_get}\/(\S+)/).join
        place="#{dir_put}/#{stub}"
        case
        when File.file?(f)
          unless act==:dryrun
            cp_r(f,place)
            Utils.chmod_util(place)
          else
            puts "--> #{place}"
          end
        when File.directory?(f)
          unless FileTest.directory?(place)
            unless act==:dryrun
              mkdir(place)
            else
              puts "mkdir -p #{place}"
            end
          end
        end
      end
    rescue
      puts "\n\n[ are you root? required for install ]"
    end
  end
end
module Version_info
  def self.contents(vi,rel=:release)
    release=rel ==:pre_release \
    ? '_pre_rel'
    : ''
    <<-WOK
---
:project: #{vi[:project]}
:version: #{vi[:version]}#{release}
:date_stamp: #{vi[:date_stamp]}
:date: "#{vi[:date]}"
    WOK
  end
  def self.git_version_extract
    if FileTest.file?('/usr/bin/git')
      x=`git describe --long --tags 2>&1`.strip.
        gsub(/^[a-z_-]*([0-9.]+)/,'\1').
        gsub(/([^-]*-g)/,'r\1').
        gsub(/-/,'.')
      x=(x=~/^[0-9]+\.[0-9]+\.[0-9]+\.r[0-9]+\.g[0-9a-f]{7}/) \
      ? x
      : nil
    else nil
    end
  end
  def self.version_number(vi)
    vi[:version]
  end
  def self.version_number_use(vi)
    (git_version_extract.nil?) \
    ? (vi[:version])
    : git_version_extract
  end
  def self.version_number_info(vi)
    (Version_info.version_number_use(vi) != vi[:version_number]) \
    ? (%{#{vi[:version_number]} from git #{Version_info.version_number_use(vi)}})
    : vi[:version_number]
  end
  def self.version_number_info_stable
    vi=Version_info::Current.setting_stable
    (Version_info.version_number_use(vi) != vi[:version_number]) \
    ? (%{#{vi[:version_number]} from git #{Version_info.version_number_use(vi)}})
    : vi[:version_number]
  end
  module Current
    def self.yml_file_path
      'data/sisu/version.yml'
    end
    def self.settings(file)
      v="#{Dir.pwd}/#{file}"
      if File.exist?(v)
        YAML::load(File::open(v))
      else ''
      end
    end
    def self.changelog_file_stable
      'data/doc/sisu/CHANGELOG_v7'
    end
    def self.file_stable
      yml_file_path
    end
    def self.setting_stable
      hsh=settings(file_stable)
      hsh[:version_number]=/([0-9]+\.[0-9]+\.[0-9]+)/.
        match(hsh[:version])[1]
      hsh
    end
    def self.version_number
      Version_info::Current.setting_stable[:version_number]
    end
    def self.content_stable
      Version_info.contents(setting_stable)
    end
  end
  module Next
    def self.settings(v)
      {
        project:        "#{Project_details.name}",
        version:        "#{v}",
        date:           "#{Utils.system_date}",
        date_stamp:     "#{Utils.system_date_stamp}",
      }
    end
    def self.setting_stable
      settings(SiSU_version)
    end
    def self.content_stable(rel)
      Version_info.contents(setting_stable,rel)
    end
  end
  module Update
    def self.version_number(vi)
      /([0-9]+\.[0-9]+\.[0-9]+)/.match(vi[:version])[1]
    end
    def self.version_number_stable
      vi=Version_info::Current.setting_stable
      /([0-9]+\.[0-9]+\.[0-9]+)/.match(vi[:version])[1]
    end
    def self.version_info_update_commit(filename,vi_hash_current,vi_content_current,vi_hash_next,vi_content_next)
      ans=%{update #{Project_details.name.downcase} version info replacing:
  #{vi_hash_current.sort}
with:
  #{vi_hash_next.sort}

#{vi_content_current}
becoming:
#{vi_content_next}
proceed? }
      resp=Utils.answer?(ans)
      if resp
        fn="#{Dir.pwd}/#{filename}"
        if File.writable?("#{Dir.pwd}/.")
          file_version=File.new(fn,'w+')
          file_version << vi_content_next
          file_version.close
        else
          puts %{*WARN* is the file or directory writable? could not create #{filename}}
        end
      end
    end
    def self.update_documentation
      fn="#{Dir.pwd}/data/doc/sisu/markup-samples/manual/_sisu/sisu_document_make"
      if File.file?(fn) \
      and File.writable?(fn)
        ver_no_stable=Version_info::Current.setting_stable[:version_number]
        debian_stable='Jessie'
        debian_testing='Stretch'
        sisu_doc_make = IO.readlines(fn)
        sisu_doc_make_next=sisu_doc_make.each.map do |line|
          line=line.gsub(/(\/$\{sisu_stable\}\/,)'[0-9]+\.[0-9]+\.[0-9]+'/,"\\1'#{ver_no_stable}'").
            gsub(/(\/$\{debian_stable\}\/,)'\*\{[A-Z][a-z]+\}\*'/,
              "\\1'*{#{debian_stable}}*'").
            gsub(/(\/$\{debian_testing\}\/,)'\*\{[A-Z][a-z]+\}\*'/,
              "\\1'*{#{debian_testing}}*'")
          line
        end
        if sisu_doc_make_next.length == sisu_doc_make.length
          sisu_doc_make_file=File.new(fn,'w+')
          sisu_doc_make_next.flatten.each do |line|
            sisu_doc_make_file << line
          end
          sisu_doc_make_file.close
        else puts "expected changelog arrays to have same length, in: #{pkgbuild.length}, out: #{pkgbuild_next.length}"
        end
      end
    end
    def self.update_stable(rel=:release)
      version_info_update_commit(
        Version_info::Current.file_stable,
        Version_info::Current.setting_stable,
        Version_info::Current.content_stable,
        Version_info::Next.setting_stable,
        Version_info::Next.content_stable(rel),
      )
    end
    def self.update_pkgbuild_stable(rel=:release)
      vn=version_number_stable
      ans=%{update PKGBUILD version info:
pkgver=#{vn}

proceed? }
      resp=Utils.answer?(ans)
      if resp
        filename='PKGBUILD_tar_xz'
        fn="#{Dir.pwd}/setup/#{filename}"
        if File.writable?(fn)
          pkgbuild = IO.readlines(fn)
          pkgbuild_next=pkgbuild.each.map do |line|
            if line =~/^\s*pkgver=/
              line=line.gsub(/^\s*(pkgver=)[0-9.]+/,"\\1#{vn}")
            else line
            end
          end
          if pkgbuild.length == pkgbuild_next.length
            pkgbuild_file=File.new(fn,'w+')
            pkgbuild_next.flatten.each do |line|
              pkgbuild_file << line
            end
            pkgbuild_file.close
          else puts "expected changelog arrays to have same length, in: #{pkgbuild.length}, out: #{pkgbuild_next.length}"
          end
        end
      end
    end
    def self.changelog_header(vi)
      vn=version_number(vi)
      <<-WOK
* sisu_#{vn}.orig.tar.xz (#{vi[:date]}:#{vi[:date_stamp].gsub(/20\d\dw/,'')})
  http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=log;h=refs/tags/sisu_#{vn}
      WOK
    end
    def self.changelog_header_release(filename,ch,vi)
      ans=%{update #{Project_details.name.downcase} changelog header, open version:

  #{ch}
proceed? }
      resp=Utils.answer?(ans)
      if resp
        fn="#{Dir.pwd}/#{filename}"
        if File.writable?(fn)
          changelog_arr_current = IO.readlines(fn)
          changelog_arr_next=changelog_arr_current.each.map do |line|
            if line =~/^\*\s+sisu_[0-9]+\.[0-9]+\.[0-9]+(?:_pre_rel)?\.orig\.tar\.xz \(Open commit window: [0-9]{4}-[0-9]{2}-[0-9]{2}; Pre-Release\)$/
              "* sisu_#{vi[:version]}.orig.tar.xz " \
              + "(#{vi[:date]}:#{vi[:date_stamp].gsub(/20\d\dw/,'')})\n"
            else line
            end
          end
          if changelog_arr_current.length == changelog_arr_next.length
            changelog_file=File.new(fn,'w+')
            changelog_arr_next.flatten.each do |line|
              changelog_file << line
            end
            changelog_file.close
          else puts "expected changelog arrays to have same length, in: #{changelog_arr_current.length}, out: #{changelog_arr_next.length}"
          end
        else
          puts %{*WARN* is the file or directory writable? could not create #{filename}}
        end
      end
    end
    def self.changelog_header_stable_filename
      Version_info::Current.changelog_file_stable
    end
    def self.changelog_header_stable
      ch=changelog_header(Version_info::Current.setting_stable)
      changelog_header_release(
        changelog_header_stable_filename,
        ch,
        Version_info::Current.setting_stable
      )
    end
    def self.changelog_header_pre_release(vi)
      vn=version_number(vi)
      <<-WOK
* sisu_#{vn}.orig.tar.xz (Open commit window: #{vi[:date]}; Pre-Release)
  http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=log;h=refs/tags/sisu_#{vn}
      WOK
    end
    def self.changelog_header_pre_release_write(filename,ch)
      ans=%{update #{Project_details.name.downcase} changelog header, open version:

  #{ch}
proceed? }
      resp=Utils.answer?(ans)
      if resp
        fn="#{Dir.pwd}/#{filename}"
        if File.writable?(fn)
          changelog_arr_current = IO.readlines(fn)
          changelog_arr_next=changelog_arr_current.each.map do |line|
            if line =~/^--- HEAD ---$/
              line << ("\n" + ch)
            else line
            end
          end
          if changelog_arr_current.length == changelog_arr_next.length
            changelog_file=File.new(fn,'w+')
            changelog_arr_next.flatten.each do |line|
              changelog_file << line
            end
            changelog_file.close
          else puts "expected changelog arrays to have same length, in: #{changelog_arr_current.length}, out: #{changelog_arr_next.length}"
          end
        else
          puts %{*WARN* is the file or directory writable? could not create #{filename}}
        end
      end
    end
    def self.changelog_header_stable_pre_release
      ch=changelog_header_pre_release(Version_info::Current.setting_stable)
      changelog_header_pre_release_write(changelog_header_stable_filename,ch)
    end
    def self.commit_changelog(rel=:release,msg)
      system(%{
        git commit -a -m"#{msg}"
        git commit --amend
      })
    end
    def self.tag_upstream
      system(%{
        git tag -a sisu_#{SiSU_version} -m"SiSU #{SiSU_version}"
      })
    end
    def self.changelog_header_commit(rel=:release)
      msg=(rel == :pre_release) \
      ? "version & changelog, open commit window"
      : "version & changelog, tag for release"
      ans=%{commit #{msg}:\n\nproceed? }
      resp=Utils.answer?(ans)
      if resp
        commit_changelog(rel,msg)
      end
    end
    def self.changelog_header_commit_tag_upstream(rel=:release)
      msg=(rel == :pre_release) \
      ? "version & changelog, open commit window"
      : "version & changelog, tag for release"
      ans=%{commit #{msg}:\n\nproceed? }
      resp=Utils.answer?(ans)
      if resp
        commit_changelog(rel,msg)
        tag_upstream
      end
    end
  end
  self
end
module GitExtractTaggedVersionBuild
  def upstream
    system(%{ git checkout upstream })
  end
  def self.git_tagged_versions(tag=nil)
    if tag
      v=if  tag =~/sisu_[0-9](?:\.[0-9]){0,2}$/ then tag
      elsif tag =~/^[0-9](?:\.[0-9]){0,2}$/     then 'sisu_' + tag
      else                                           'sisu_'
      end
      system(%{ git tag -l | ag --nocolor '^#{v}' })
    end
  end
  def self.git_checkout_and_build_and_install_version(tag,options)
    begin
      ver=if tag =~/sisu_[0-9]\.[0-9]+\.[0-9]+/ then tag
      elsif  tag =~/^[0-9]\.[0-9]+\.[0-9]+/     then 'sisu_' + tag
      else                                           branch
      end
      create=options[:create] ? '--create ' : ''
      build=options[:build] ? '--build ' : ''
      install=options[:install] ? '--install ' : ''
      commands =<<-WOK
        git checkout #{ver} &&
        #{$called_as} gem #{ver} #{create}#{build}#{install};
      WOK
      puts commands
      begin
        system(commands)
      rescue
      end
    rescue
    ensure
      system(%{
        git checkout upstream
      })
    end
  end
end
module Gemspecs
  def self.info(vi)
    puts <<-WOK
--
name:       #{vi[:project].downcase}
version:    #{vi[:version_number]}
date:       #{vi[:date]}
summary:    #{vi[:project]}
    WOK
  end
  def self.contents(vi)
    <<-WOK
Gem::Specification.new do |s|
  s.name           = '#{vi[:project].downcase}'
  s.version        = '#{vi[:version_number]}'
  s.date           = '#{vi[:date]}'
  s.summary        = '#{Project_details.summary} (linux calls)'
  s.description    = '#{Project_details.description} [#{Version_info.version_number_info(vi)}] (linux calls & without external dependencies)'
  s.homepage       = '#{Project_details.homepage}'
  s.authors        = ["Ralph Amissah"]
  s.email          = 'ralph.amissah@gmail.com'
  s.license        = 'GPL3'
  s.files          = Dir['lib/#{Project_details.name.downcase}.rb'] +
                     Dir['lib/#{Project_details.name.downcase}/*.rb'] +
                     Dir['data/#{Project_details.name.downcase}/version.yml'] +
                     Dir['data/#{Project_details.name.downcase}/image/*'] +
                     Dir['bin/#{Project_details.name.downcase}gem'] +
                     Dir['bin/#{Project_details.name.downcase}']
  s.executables << '#{Project_details.name.downcase}gem' << '#{Project_details.name.downcase}'
  s.has_rdoc       = false
end
    WOK
  end
  def self.contents_git(vi)
    <<-WOK
Gem::Specification.new do |s|
  s.name           = '#{vi[:project].downcase}'
  s.version        = '#{Version_info.version_number_use(vi)}'
  s.date           = '#{vi[:date]}'
  s.summary        = '#{Project_details.summary} (linux calls)'
  s.description    = '#{Project_details.description} [#{Version_info.version_number_info(vi)}] (linux calls & without external dependencies)'
  s.homepage       = '#{Project_details.homepage}'
  s.authors        = ["Ralph Amissah"]
  s.email          = 'ralph.amissah@gmail.com'
  s.license        = 'GPL3'
  s.files          = `git ls-files -z lib`.split("\x0") +
                     Dir['data/#{Project_details.name.downcase}/version.yml'] +
                     Dir['data/#{Project_details.name.downcase}/image/*'] +
                     Dir['bin/#{Project_details.name.downcase}gem'] +
                     Dir['bin/#{Project_details.name.downcase}']
  s.executables << '#{Project_details.name.downcase}gem' << '#{Project_details.name.downcase}'
  s.has_rdoc       = false
end
    WOK
  end
  def self.create(filename,gemspec)
    fn="#{Dir.pwd}/#{filename}.gemspec"
    if File.writable?("#{Dir.pwd}/.")
      file_sisu_gemspec=File.new(fn,'w+')
      file_sisu_gemspec << gemspec
      file_sisu_gemspec.close
    else
      puts %{*WARN* is the file or directory writable? could not create #{filename}}
    end
  end
  def self.build(fn)
    system(%{ gem build #{fn}.gemspec })
  end
  def self.install(vn)
    system(%{
      sudo gem install --local --no-document --verbose sisu-#{vn}.gem
    })
  end
  module Current
    def self.filename
      Project_details.name.downcase
    end
    def self.filename_stable
      Project_details.name.downcase \
      + '-' \
      + Version_info::Current.setting_stable[:version_number]
    end
    def self.info_stable
      Gemspecs.info(Version_info::Current.setting_stable)
    end
    def self.current_stable
      Gemspecs.contents(
        Version_info::Current.setting_stable,
      )
    end
    def self.current_git_version
      Gemspecs.contents_git(
        Version_info::Current.setting_stable,
      )
    end
    def self.create_stable(version=:version_standard)
      (version==:version_git) \
      ? (Gemspecs.create(filename,current_git_version))
      : (Gemspecs.create(filename,current_stable))
    end
    def self.build_stable
      Gemspecs.build(filename)
    end
    def self.install_stable(version=:version_standard)
      vi=Version_info::Current.setting_stable
      vn=((version==:version_git) \
      && (Version_info.version_number_use(vi) != vi[:version_number])) \
      ? (Version_info.version_number_use(vi))
      : (vi[:version_number])
      Gemspecs.install(vn)
    end
  end
end
module Package
  def self.sequence
    puts <<-WOK
  --open-version                # update package version
  --version-and-tag-for-release # git tags upstream version
  # not included:
  # --merge                     # git merge upstream tag into debian/sid
  # --dch                       # dch create and edit
  # --dch-commit                # dch commit
  # --build                     # git-buildpackage
  # --git_push                  # git push changes
  # --dput                      # dput package
  # --reprepro_update           # reprepro update
  # --reprepro_push             # reprepro rsync changes
    WOK
  end
end
__END__
