#!/usr/bin/env ruby

# echo-add-icon: Script for echo-icon-theme artists to add new icon set to local
# git repository 
#
# Copyright (C) 2008, Martin Sourada
# Derived from jimmac's script (http://pastebin.ca/1071599) 
#
# This script is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# 
# This script 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
# Lesser General Public License for more details.
# 
# You should have received a copy of the GNU Lesser General Public
# License along with this script; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA


require "rexml/document"
require "ftools"
include REXML
INKSCAPE = '/usr/bin/inkscape'
BRANCHES_LEGACY = ['0.3.x', '0.3.2.x']
BRANCHES_AUTOTOOLS = ['master']
SIZES = ['16x16', '22x22', '24x24', '32x32', '48x48', '256x256', 'scalable']

def printusage()
  puts "\nUsage:"
  puts "one-canvas.rb <echo-git-direcory> <source-file>"
end

def run(cmd)
  puts "\n$ #{cmd}"
  return system(cmd)
end

def get_symlinks(file)
  icon_mapping = "/usr/share/icon-naming-utils/legacy-icon-mapping.xml"
  icon_name = "#{File.basename(file,'.svg')}"
  symlinks = []

  icon_map = Document.new(File.new(icon_mapping, 'r'))

  icon = icon_map.root.elements["//icon[@name='#{icon_name}']"]

  if icon != nil
    icon.each_element('link') do |link|
      symlinks = symlinks + [link.text]
    end
  end

  add = "y"
  while add == "y"
    puts "\nCurrent list of symlinks to be added:"
    symlinks = symlinks.sort
    puts symlinks
    puts "\nAdd another symlink (leave empty for no another symlink):"
    symlink = $stdin.gets.delete "\n"
    if symlink == ""
      add = "n"
    else
      symlinks = symlinks + [symlink]
    end
  end

  return symlinks
end

def add_symlinks_legacy(gitdir, file, context, size, symlinks)
  icon_name = "#{File.basename(file,'.svg')}"

  if size == "scalable"
    ext = "svg"
  else
    ext = "png"
  end
  
  if File.exist?("#{gitdir}/base/#{size}/#{context}/#{icon_name}.#{ext}")
    symlinks.each do |link|
      symlink = "#{gitdir}/base/#{size}/#{context}/#{link}.#{ext}"
      if !File.exist?(symlink)
        File.symlink("#{icon_name}.#{ext}", symlink)
      end
    end
    puts "symlinks added"
  end
end

def renderit(gitdir, file)
  svg = Document.new(File.new("#{file}", 'r'))
  context = svg.root.elements['//dc:description'].text

  svg.root.each_element("//g[@inkscape:label='plate']/rect") do |icon|
    size = "#{icon.attributes['width']}x#{icon.attributes['height']}"
    dir = "#{gitdir}/base/#{size}/#{context}"
    File.makedirs(dir) unless File.exists?(dir)
    run "#{INKSCAPE} -i #{icon.attributes['id']} -e #{dir}/#{File.basename(file,'.svg')}.png #{file} > /dev/null 2>&1"
  end

  return context
end

def expungeit(gitdir, file)
  svg = Document.new(File.new("#{file}"), 'r')

  context = svg.root.elements['//dc:description'].text
  plate = svg.root.elements["//g[@inkscape:label='plate']/rect[@inkscape:label='scalable']"]
  x = plate.attributes['x']
  y = plate.attributes['y']

  artwork = svg.root.elements["//g[@inkscape:label='artwork']/g[@inkscape:label='scalable']"]
  translate = "translate(-#{x},-#{y})"
  artwork.add_attribute(Attribute.new('transform', translate))

  canvas = svg.root.elements["/svg"]
  canvas.add_attribute(Attribute.new('width', '48'))
  canvas.add_attribute(Attribute.new('height', '48'))

  plate = svg.root.elements["//g[@inkscape:label='plate']"]
  plate.elements.delete_all('')

  svg.root.each_element("//g[@inkscape:label='artwork']/*") do |obj|
    label = obj.attributes['inkscape:label']
    if (label != 'scalable')
      obj.parent.delete_element(obj)
    end
  end

  dir = "#{gitdir}/base/scalable/#{context}"
  out ="#{dir}/#{File.basename(file)}"
  File.makedirs(dir) unless File.exists?(dir)

  f = File.open(out,"w")
  svg.write(f, -1, false)
  f.close

  run "#{INKSCAPE} --vacuum-defs -l #{out} -f #{out}"
  return context
end

def addsource(gitdir, file, context)
  dir = "#{gitdir}/sources/base/one-canvas/#{context}"
  File.makedirs(dir) unless File.exists?(dir)
  File.copy(file, "#{dir}/#{File.basename(file)}", true)
end

def updategit(gitdir, branch)
  puts "Updating branch #{branch} for git repository located at:\n#{gitdir}\n"
  run "cd #{gitdir} && git pull origin"
end

def askbranches(gitdir)
  puts "\nAvailable branches are:"
  run "cd #{gitdir} && git branch"
  puts "Which branch do you want to commit the icon to?"
end

def get_symlinks_autotools(file)
  icon_mapping = "/usr/share/icon-naming-utils/legacy-icon-mapping.xml"
  icon_name = "#{File.basename(file,'.svg')}"
  symlinks = []

  icon_map = Document.new(File.new(icon_mapping, 'r'))

  icon = icon_map.root.elements["//icon[@name='#{icon_name}']"]

  if icon != nil
    icon.each_element('link') do |link|
      symlinks = symlinks + [link.text]
    end
  end
  symlinks_all = symlinks
   
  add = "y"
  while add == "y"
    puts "\nCurrent list of symlinks to be added:"
    symlinks_all = symlinks_all.sort
    puts symlinks_all
    puts "\nAdd another symlink (leave empty for no another symlink):"
    symlink = $stdin.gets.delete "\n"
    if symlink == ""
      add = "n"
    else
      symlinks_all = symlinks_all + [symlink]
    end
  end

  symlinks_user = symlinks_all - symlinks

  return symlinks_user
end

def add_new_icon(file, content, ext)
  icons_data = false
  icons = []
  is_in = false
  content.each do |line|
    if line.include?("icons_DATA")
      icons_data = true
    elsif icons_data
      if line.include?("#{file}")
        is_in = true
      end
      if !line.include?("\\")
        icon = line.rstrip.delete "\\"
        icon = icon.delete " "
        icons = icons + [icon]
        icons_data = false
      else
        icon = line.rstrip.delete "\\"
        icon = icon.delete " "
        icons = icons + [icon]
      end
    end
  end

  if !is_in
    icons = icons + ["\t#{file}.#{ext}"]
  end

  icons.delete("")

  return icons.sort
end

def add_new_symlinks(file, content, symlinks, ext)
  symlinks_new = []
  install_local = false; 

  content.each do |line|
    if line.include?("install-data-local")
      install_local = true
    elsif install_local
      if line.rstrip == ""
        install_local = false
      else
        symlink = line
        symlinks.each do |link|
          if line.include?(link)
            symlinks = symlinks - [link]
          end
        end
        symlinks_new = symlinks_new + [symlink]
      end
    end
  end

  symlinks.each do |symlink|
    symlinks_new = symlinks_new + ["\t(cd $(DESTDIR)$(themedir)/$(size)/$(context) && $(LN_S) #{file}.#{ext} #{symlink}.#{ext})"]
  end
 
  return symlinks_new
end

def update_autotools(gitdir, file, context, size, symlinks)
  icon_name = "#{File.basename(file,'.svg')}"
  makefile = "#{gitdir}/base/#{size}/#{context}/Makefile.am"

  if size == "scalable"
    ext = "svg"
  else
    ext = "png"
  end

  if File.exist?("#{gitdir}/base/#{size}/#{context}/#{icon_name}.#{ext}")
    content = IO.readlines("#{makefile}")

    f = File.new(makefile, "w")  
 
    icons_data = false
    extra_dist = false
    install_data_local = false
    noprint = false

    content.each do |line|
      if line.rstrip == ""
        noprint = false
      elsif line.include?("icons_DATA =")
        noprint = true
        icons_data = true
        icons = add_new_icon(icon_name, content, ext)
        f.puts "icons_DATA = \\"
        icons.each do |icon|
          if icon == icons.last
            f.puts "#{icon}"
          else
           f.puts "#{icon} \\"
          end
        end
      elsif line.include?("EXTRA_DIST")
        noprint = true
        extra_dist = true
        f.puts "EXTRA_DIST = $(icons_DATA)"
      elsif line.include?("install-data-local")
        noprint = true
        install_data_local = true
        symlinks_add = add_new_symlinks(icon_name, content, symlinks, ext)
        f.puts "install-data-local: install-iconsDATA"
        symlinks_add.each do |symlink|
          f.puts "#{symlink}"
        end
      end
      if !noprint
        f.puts "#{line}"
      end
    end

    if !icons_data
      icons = add_new_icon(icon_name, content, ext)
      f.puts "icons_DATA = \\"
      icons.each do |icon|
        if icon == icons.last
          f.puts "#{icon}"
        else
          f.puts "#{icon} \\"
        end
      end
      f.puts ""
    end

    if !extra_dist
      f.puts "EXTRA_DIST = $(icons_DATA)"
      f.puts ""
    end
  
    if !install_data_local and !symlinks.empty?
      symlinks_add = add_new_symlinks(icon_name, content, symlinks, ext)
      f.puts "install-data-local: install-iconsDATA"
      symlinks_add.each do |symlink|
        f.puts "#{symlink}"
      end
      f.puts ""
    end
  
    f.close
  end
end
  
def push_branch_specific(gitdir, file, context, branch)
  if BRANCHES_LEGACY.include?(branch)
    symlinks = get_symlinks(file)
    SIZES.each do |size|
      add_symlinks_legacy(gitdir, file, context, size, symlinks)
    end
  elsif BRANCHES_AUTOTOOLS.include?(branch)
    symlinks = get_symlinks_autotools(file)
    SIZES.each do |size|
      update_autotools(gitdir, file, context, size, symlinks)
    end
  end
end

def pushit(gitdir, file)
  continue = "y"
  while continue!= "n"
    askbranches(gitdir)
    branch = $stdin.gets.delete "\n"

    if run("cd #{gitdir} && git checkout #{branch}")
      updategit(gitdir,branch)

      puts "Rendering PNGs from #{file}:"
      renderit(gitdir, file)
      puts "\nDone."

      print "Creating scalable icon from #{file}:"
      context = expungeit(gitdir, file)
      puts "\nDone."

      addsource(gitdir, file, context)
      
      puts "\nDo you want to make branch specific changes[y/n]?"
      changes = $stdin.read(1)
      $stdin.gets
      
      if changes == "y"
        push_branch_specific(gitdir, file, context, branch)
      else
        puts "[M] Make sure to also do branch specific changes."
      end

      puts "\nCommiting to branch #{branch}"
      if run("cd #{gitdir} && git add * && git commit -a")
        puts "\nDone."
        puts "\nIcons added successfully to git."
      else
        $stderr.puts "\n[E] Failed."
      end
    else
      $stderr.puts "\n[E] Non-existant branch."
    end
    
    print "\nDo you want to commit to another branch[y/n]? "
    continue = $stdin.read(1)
    $stdin.gets
  end
end

gitdir = "#{ARGV[0]}"
file = "#{ARGV[1]}"
if (File.exists?("#{gitdir}/.git/config"))
  if (File.exists?("#{gitdir}/sources/generate-status-table/generate-status-table.c"))
    if (File.exists?("#{file}"))
      pushit(gitdir,file)
      puts "[M] Now push the changes back to git repo at fedora hosted."
    else
      $stderr.puts "[E] No such file (#{file})"
      printusage()
    end
  else
    $stderr.puts "[E] The given directory does not look like correct echo-icon-theme git\nrepository."
    printusage()
  end
else
  $stderr.puts "[E] There is no git repository in #{gitdir}"
  printusage()
end

