# encoding: utf-8

# Copyright (C) 2011 Clemens Fuchslocher <clemens@vakuumverpackt.de>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# 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.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

require 'fileutils'
require 'java'

require_relative 'Renderer'

java_import java.awt.BasicStroke
java_import java.awt.Color
java_import java.awt.Font
java_import java.io.FileOutputStream
java_import org.jfree.chart.ChartFactory
java_import org.jfree.chart.ChartRenderingInfo
java_import org.jfree.chart.ChartUtilities
java_import org.jfree.chart.entity.StandardEntityCollection
java_import org.jfree.chart.imagemap.ImageMapUtilities
java_import org.jfree.chart.labels.PieSectionLabelGenerator
java_import org.jfree.chart.plot.PieLabelLinkStyle
java_import org.jfree.chart.urls.PieURLGenerator
java_import org.jfree.data.general.DefaultPieDataset
java_import org.jfree.util.Rotation

module VoidMeter

	class ChartRenderer < Renderer
		def initialize(projects, results, path)
			@projects = projects
			@results = results
			@path = "#{path}/charts"
			mkdir(@path)
		end

		def render
			@projects.each do |project|
				puts "VoidMeter::ChartRenderer#render: project.name == #{project.name}"
				project.releases.each do |release|
					puts "VoidMeter::ChartRenderer#render: release.version == #{release.version}"

					filename = "#{project.name}-#{release.version}".downcase

					result = @results.get_result(project.name, release.version) || Hash.new
					indents = result[:indents] || Hash.new(0)
					totals = result[:totals] || Hash.new(0)

					lines = totals[:lines] || 0
					trailing = indents[:trailing] || 0
					nicely = lines - trailing

					chart = Chart.new
					chart.add_sector(:not, percent(lines, indents[:not]), 'Not', 0xDDDF00)
					chart.add_sector(:tabs, percent(lines, indents[:tabs]), 'Tabs', 0x50B432)
					chart.add_sector(:spaces, percent(lines, indents[:spaces]), 'Spaces', 0x058DC7)
					chart.add_sector(:both, percent(lines, indents[:both]), 'Both', 0xED561B)
					chart.add_sector(:block_comment, percent(lines, indents[:block_comment]), "Block\ncomment", 0x24CBE5)
					chart.render(filename, 'results/charts')

					chart_trailing = Chart.new
					chart_trailing.add_sector(:nicely, percent(lines, nicely), "Nicely\nended", 0x058DC7)
					chart_trailing.add_sector(:trailing, percent(lines, trailing), "Trailing\nspaces", 0x50B432)
					chart_trailing.render("#{filename}-trailing", 'results/charts')

					release.chart = chart
					release.chart_trailing = chart_trailing
				end
			end
		end

		private

		def percent(total, number)
			(100.0 / total) * number
		end
	end

	class Chart
		attr_reader :filename, :imagemap, :imagemap_name

		def initialize
			@sectors = []
			@sectorsLookup = {}
		end

		def add_sector(sectorId, value, label, color)
			if value > 0
				sector = Sector.new(sectorId, value, label, color)
				@sectors.push(sector)
				@sectorsLookup[sectorId] = sector
			end
		end

		def render(filename, path)
			dataset = DefaultPieDataset.new

			@sectors.each do |sector|
				dataset.set_value(sector.sectorId, sector.value)
			end

			chart = ChartFactory.createPieChart('', dataset, false, true, false)
			chart.set_anti_alias(true)
			chart.set_background_paint(Color::WHITE)

			plot = chart.get_plot
			plot.set_background_paint(Color::WHITE)
			plot.set_base_section_outline_paint(Color::WHITE)
			plot.set_base_section_outline_stroke(BasicStroke.new(2))
			plot.set_direction(Rotation::CLOCKWISE)
			plot.set_interior_gap(0.02)
			plot.set_label_background_paint(nil)
			plot.set_label_font(Font.new('Bitstream Vera Sans Mono', Font::PLAIN, 12))
			plot.set_label_gap(0)
			plot.set_label_generator(LabelGenerator.new(@sectorsLookup))
			plot.set_label_link_margin(0.02)
			plot.set_label_link_style(PieLabelLinkStyle::STANDARD)
			plot.set_label_outline_paint(nil)
			plot.set_label_shadow_paint(nil)
			plot.set_maximum_label_width(0.16)
			plot.set_outline_visible(false)
			plot.set_shadow_xoffset(0)
			plot.set_shadow_yoffset(0)
			plot.set_url_generator(UrlGenerator.new)

			@sectors.each do |sector|
				plot.set_section_paint(sector.sectorId, Color.new(sector.color))
			end

			info = ChartRenderingInfo.new(StandardEntityCollection.new)

			@filename = "#{filename}.png"
			file = FileOutputStream.new("#{path}/#{@filename}")
			ChartUtilities.write_chart_as_png(file, chart, 374, 374, info)
			file.close

			@imagemap_name = filename.gsub('.', '-')
			@imagemap = ImageMapUtilities.getImageMap(@imagemap_name, info, ToolTipFragmentGenerator.new, UrlFragmentGenerator.new(@imagemap_name))
			@imagemap = @imagemap.gsub('/>', '>')
		end

		private

		class Sector
			attr_reader :sectorId, :value, :label, :color

			def initialize(sectorId, value, label, color)
				@sectorId = sectorId
				@value = value
				@label = label
				@color = color
			end
		end

		class LabelGenerator
			def initialize(sectorsLookup)
				@sectorsLookup = sectorsLookup
			end

			def generate_section_label(dataset, comparable)
				sector = @sectorsLookup[comparable]
				if sector.nil?
					return comparable.to_s
				end
				sector.label + "\n%.2f%" % sector.value
			end

			def generate_attributed_section_label(dataset, comparable)
				nil
			end
		end

		class UrlGenerator
			def generate_url(dataset, comparable, index)
				comparable.to_s
			end
		end

		class ToolTipFragmentGenerator
			def generate_tool_tip_fragment(text)
				''
			end
		end

		class UrlFragmentGenerator
			def initialize(imagemap_name)
				@imagemap_name = imagemap_name.gsub('-trailing', '')
			end

			def generate_url_fragment(sectorId)
				%{ nohref="nohref" onmouseover="VoidMeter.selectSector('#{@imagemap_name}', '#{sectorId.downcase}');" alt=""}
			end
		end
	end

end
