#  Draco Econometrics
#  Copyright (C) 2009 Approximatrix, LLC
#  http://www.approximatrix.com
#  
#  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 3 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, see <http://www.gnu.org/licenses/>.

import java.lang.System
import com.approximatrix.draco.application.plugin.PluginType

# These imports allow access to the Apache Commons Math library,
# which is distributed with Draco
import org.apache.commons.math.stat.descriptive.moment.Kurtosis
import org.apache.commons.math.stat.descriptive.moment.Skewness


require 'pengine/model/analysis_plugin'
include Math

class ExtendedStatistics < Plugin::AnalysisPluginSkeleton
  @@NAME = "Extended Statistics"
  
  def initialize(model)
    super(model)
    # We won't be using the text field here
	@text = nil
    @failure = nil
    
    @arithmetic_mean = 0
    @geometric_mean = nil
    @harmonic_mean = nil
    
    @median = nil
    
    @stdev = nil
    @coefvariation = nil
    
  end
  
  def initialize_columns
    @selectioncolumns.add ExtendedStatistics.createColumn('Selection', false, true)
    @selectioncolumns
  end
  
  def run
  	
  	# Determine and retrieve the selected column here
  	var = selections(0)
  	if(var.length == 0)
  	  @failure = "No variable selected for analysis."
  	  return
  	end
  	data = @model.to_matrix(var).column(0)
  	
  	# We now have a vector of values to work with
  	# Compute some means in parallel
  	tamean = Thread.new { @arithmetic_mean = data.mean }
  	tgmean = Thread.new do
  	  @geometric_mean = 1.0
  	  power = (1.0/data.length)
  	  data.each do |x|
  	    @geometric_mean = @geometric_mean*(x**power)
  	  end
  	end
  	thmean = Thread.new do
  	  @harmonic_mean = 0.0
  	  data.each do |x|
  	    if(x == 0.0)
  	      @harmonic_mean = nil
  	      break
  	    end
  	    @harmonic_mean = @harmonic_mean+(1.0/x)
  	  end
  	  if(not @harmonic_mean.nil?)
  	    if(@harmonic_mean == 0)
  	      @harmonic_mean = nil
  	    else
  	      @harmonic_mean = (1.0*data.length)/@harmonic_mean
  	    end
  	  end
  	end
  	tmedian = Thread.new { @median = data.median }
  	[thmean,tgmean,tamean,tmedian].each { |x| x.join }
  	
  	statistic "Arithmetic Mean", @arithmetic_mean
  	statistic "Geometric Mean", @geometric_mean
  	statistic "Harmonic Mean", @harmonic_mean
  	statistic "Median",@median
  	
  	@stdev = data.standard_deviation
  	statistic "Standard Deviation", @stdev
  	statistic("Coefficient of Variation",@stdev/@arithmetic_mean) unless @arithmetic_mean == 0.0
  	statistic "Variance", @stdev*@stdev
  	
  	# We need the third and fourth moments for computing the 
  	# skewness and kurtosis by calling the Apache Commons Math
  	# library.  Note that the data vector must call "to_java"
  	# to create a passable java array
  	kurtosis = 0.0
  	skewness = 0.0
  	tskew = Thread.new do
  	  skewness = Skewness.new
  	  skewness = skewness.evaluate(data.to_java,0,data.length)
  	end
  	tkurt = Thread.new do
  	  kurtosis = Kurtosis.new
  	  kurtosis = kurtosis.evaluate(data.to_java,0,data.length)
  	end
  	
    [tskew, tkurt].each { |x| x.join }
  	
  	# Skewness
  	statistic "Skewness", skewness
  	
  	# Kurtosis
  	statistic "Excess Kurtosis", kurtosis 
  	
  end
  
end

register(ExtendedStatistics)
