require "fileutils"

Dependencies.require_or_load "execute_analysis"

def array_type(type)
  if /array_(.*)$/ =~ type.to_s
    type = [$1.to_sym]
  else
    type = [:string]
  end
  return type
end

class DrawParams < ActionWebService::Struct
  Analysis.columns.each{|column|
    name = column.name
    next if /function/ =~ name
    next if %w(variables action_type anim anim_dim input_num).include?(name)
    type = column.type
    if name == "region"
      type = [[:float]]
    elsif /array/ =~ type.to_s
      type = array_type(type)
    end
    member name, type
  }
end

class AnalysisParams < ActionWebService::Struct
  Analysis.columns.each{|column|
    name = column.name
    next unless /function/ =~ name
    type = column.type
    if /array/ =~ type.to_s
      type = array_type(type)
    elsif type == :model
      type = :string
    end
    member name, type
  }
end


class WebserviceAnalysisApi < ActionWebService::API::Base
  api_method :draw, :expects => [{:variables => [:string]}, {:params => DrawParams}], :returns => [[:string]]
  api_method :analysis, :expects => [{:variables => [:string]}, {:params => AnalysisParams}], :returns => [[:string]]
end

class WebserviceAnalysisService < ActionWebService::Base
  include ExecuteAnalysis

  web_service_api WebserviceAnalysisApi

  def initialize(request)
    @request = request
  end

  def draw(variables, params)
    params = params_to_hash(params)
    analysis = variables_set( variables )
    analysis.attributes = params
    analysis.action_type = 0
    res = get_diagram(analysis, true)
    delete_work
    if res[0]
      return res[1].collect{|dg| diagram_to_dginfo(dg)}.collect{|di|
        url_prefix + di[1]
      }
    else
      return nil
    end
  end

  def analysis( variables, params )
    params = params_to_hash(params)
    analysis = variables_set( variables )
    analysis.attributes = params
    analysis.action_type = 1
    analysis.input_num = analysis.function.input_num
    vars, messages = create_new_variable(analysis, work_dir)
    if vars
      url = Array.new
      vars.each{|var|
        from,vname = var.file_and_variable_names
        path = File.temp_name(GFDNAVI_TEMP_DATA_PATH)
        dest, = dest_fname(path,"nc")
        File.move( from, dest )
        url.push( url_prefix + dest.sub(/^#{GFDNAVI_PUBLIC_PATH}/,"") + Variable::DIR_VAR_DELIMITER + vname )
      }
      delete_work
    else
      url = nil
    end
    delete_work
    return url
  end


  private
  def region_to_hash(region)
    hash = Hash.new
    region.each_with_index{|dim,i|
      case dim.length
      when 1
        hash[i.to_s] = {"min"=>dim[0].to_s}
      when 2
        hash[i.to_s] ={"min"=>dim[0].to_s, "max"=>dim[1].to_s}
      end
    }
    return hash
  end
  def params_to_hash(params)
    hash = Hash.new
    params.each_pair{|key,val|
      hash[key.to_sym] = val unless val.nil?
    }
    hash[:region] = region_to_hash(hash[:region]) if hash[:region]
    return hash
  end

  def delete_work
    FileUtils.rm_rf(work_dir)
  end

  def url_prefix
    prot = request.ssl? ? "https" : "http"
    "#{prot}://#{@request.host_with_port}#{@request.relative_url_root}"
  end

  def session
    unless @session
      @session = Hash.new
      class << @session
        def session_id
          unless @session_id
            dir = File.temp_name( File.join(GFDNAVI_WORK_PATH,"aws") )
            @session_id = dir.sub(/^#{GFDNAVI_WORK_PATH}\//,"")
          end
          @session_id
        end
      end
    end
    return @session
  end

end
