#!/usr/bin/ruby

require 'rubygems'
require 'yaml'
require 'irb'
require 'right_api_client'
require 'rest_connection'
require 'trollop'
require 'highline/import'
require 'json'

# The only option needed for this program is the ServerTemplate ID.
trollop_parser = Trollop::Parser.new do
  opt :st_id, "Generate a report for this Server Template (id)", :type => :integer
  opt :st_list_file, "Generate a list of MCIs in Server Templates given in the file", :type => :string
  opt :output_type, "Specify the type of output. Supported formats: text, xml, json", :type => :string
end

class MciReport

  # Establish a connection to Right_API_Client during the initialization  
  def initialize
    @client = RightApi::Client.new(YAML.load_file(File.expand_path('~/.right_api_client/login.yml', __FILE__)))
  end

  # This function creates a report of all the Multi Cloud Images in a ServerTemplate specified by the ST ID in the input.
  def generate_mci_report(options)
    mcis = @client.server_templates(:id => options[:st_id]).show.multi_cloud_images.index
    
    # Go through all the Multi Cloud Images in the given ServerTemplate and pull the information required for printing the report. 
    outer_hash_array = Array.new
    mcis.each do |mci|
      outer_hash = Hash.new
      # Name, Description, Revision, and MCI ID are obtained directly from the MCI object.
      mci_id = mci.href.split("/").last.to_i
      outer_hash['title'] = "Name: " + mci.name + " | MCI ID: " + mci_id.to_s + " | Revision: " + mci.show.revision.to_s + "\nDescription: " + mci.show.description      
      inner_hash_array = Array.new
      inner_hash = Hash.new
      
      # Add all titles in the first array element.
      inner_hash['detail1'] = "Instance Type"
      inner_hash['detail2'] = "Image Name"
      inner_hash['detail3'] = "Cloud"
      inner_hash_array << inner_hash
      
      # This block uses the rest_connection for obtaining information about ec2 images.
      rest_mci = MultiCloudImage.find(mci_id)
      rest_mci_settings = rest_mci.find_and_flatten_settings
      rest_mci_settings.each do |rest_mci_setting|
        mci_params = rest_mci_setting.params
        inner_hash = Hash.new
        
        # Grab only the information about the ec2 images.
        if mci_params['aws_instance_type']
	        inner_hash['detail1'] = mci_params['aws_instance_type']
          inner_hash['detail2'] = mci_params['image_name']
          inner_hash['detail3'] = mci_params['cloud']
        end
	      inner_hash_array << inner_hash if inner_hash['detail1'] && inner_hash['detail2'] && inner_hash['detail3']
      end

      # This block uses the regular right_api_client for obtaining information about non-ec2 images.
      right_mci_settings = mci.settings.index
      right_mci_settings.each do |right_mci_setting|
        inner_hash = Hash.new 
        
        # If the instance_type api method is not available, don't call the method rather print N/A for instance type in the report.
        if right_mci_setting.api_methods.include?("instance_type")
	        inner_hash['detail1'] = right_mci_setting.instance_type.show.name
        else
	        inner_hash['detail1'] = "N/A"
        end
        inner_hash['detail2'] = right_mci_setting.image.show.name
	      inner_hash['detail3'] = right_mci_setting.cloud.show.name
	      inner_hash_array << inner_hash if inner_hash['detail1'] && inner_hash['detail2'] && inner_hash['detail3']
      end
      outer_hash['detail'] = inner_hash_array
      outer_hash_array << outer_hash
    end
    self.print_report(options, outer_hash_array, "RightScale MCI Image Report")
  end


  # This function gets the name and id hash and prepares a list of ServerTemplate IDs.
  def servertemplate_list(servertemplate_name_id_hash)
    list = []
    servertemplate_name_id_hash.each do |name, id|
      list << @client.server_templates(:id => id).show
    end
    list
  end

  # This function creates a report of all ServerTemplates specified in the input file.
  def generate_servertemplate_report(options, servertemplate_name_id_hash)
    outer_hash_array = Array.new
    st_list = servertemplate_list(servertemplate_name_id_hash)
    st_list.each do |st|
      outer_hash = Hash.new
      mcis = st.multi_cloud_images.index 
      outer_hash['title'] = "Name: " + st.name + " | ID: " + st.object_id.to_s
      inner_hash_array = Array.new
      inner_hash = Hash.new
      inner_hash['detail1'] = "Revision"
      inner_hash['detail2'] = "Name"
      inner_hash['detail3'] = "MCI ID"
      inner_hash_array << inner_hash if inner_hash['detail1'] && inner_hash['detail2'] && inner_hash['detail3']
      
      # Go through all the Multi Cloud Images in the given ServerTemplate and pull the information required for printing the report.     
      mcis.each do |mci|
        inner_hash = Hash.new
        mci_id = mci.href.split("/").last.to_i
        inner_hash['detail1'] = mci.show.revision
        inner_hash['detail2'] = mci.name
        inner_hash['detail3'] = mci_id
        inner_hash_array << inner_hash if inner_hash['detail1'] && inner_hash['detail2'] && inner_hash['detail3']
      end
      outer_hash['detail'] = inner_hash_array.sort_by{ |inner_hash| inner_hash['detail2']}
      outer_hash_array << outer_hash
    end
    self.print_report(options, outer_hash_array, "RightScale MCI ServerTemplate Report")
  end
 
  def print_report(options, outer_hash_array, report_title)
    if options[:output_type] == "text"
      self.print_text_report(outer_hash_array, report_title)
    elsif options[:output_type] == "xml"
      self.print_xml_report(outer_hash_array, report_title)
    elsif options[:output_type] == "json"
      self.print_json_report(outer_hash_array, report_title)
    else
      
      # Default to text report if no type is specified
      self.print_text_report(outer_hash_array, report_title)
    end
  end

  # This functions prints the formatted report in a text file
  def print_text_report(outer_hash_array, report_title)
    report_file_name = report_title.gsub(/\s+/, "_") + ".txt"
    file_handler = File.open(report_file_name, 'w')
    current_time = Time.new
  
    file_handler.puts sprintf("%75s", "******** #{report_title} ********")
    file_handler.puts ""
    file_handler.puts "Reported generated at: " + current_time.strftime("%m/%d/%Y %H:%M:%S %Z")
    file_handler.puts ""
  
    outer_hash_array.each do |outer_hash|
      file_handler.puts '-'*100
      file_handler.puts outer_hash['title']
      file_handler.puts '-'*100
      inner_hash_array = outer_hash['detail']
      title = inner_hash_array[0]
      if title
        title_str = sprintf("%-20s", title['detail1']) + sprintf("%-65s", title['detail2']) + sprintf("%-30s", title['detail3'])
        title_line_str = sprintf("%-20s", '-'*title['detail1'].size) + sprintf("%-65s", '-'*title['detail2'].size) + sprintf("%-30s", '-'*title['detail3'].size)
        file_handler.puts "  " + title_str
        file_handler.puts "  " + title_line_str
        inner_hash_array.delete(title)
      end
      inner_hash_array.each do |inner_hash|
        detail_str = sprintf("%-20s", inner_hash['detail1']) + sprintf("%-65s", inner_hash['detail2']) + sprintf("%-30s", inner_hash['detail3'])
        file_handler.puts "  " + detail_str
      end
      file_handler.puts ""
    end
  end

  def print_xml_report(outer_hash_array, report_title)
    report_file_name = report_title.gsub(/\s+/, "_") + ".xml"
    file_handler = File.open(report_file_name, 'w')
    current_time = Time.new
    
    file_handler.puts "<mci_report>"
    file_handler.puts "<report_title>"
    file_handler.puts report_title
    file_handler.puts "</report_title>"
    file_handler.puts "<generated_time>"
    file_handler.puts current_time.strftime("%m/%d/%Y %H:%M:%S %Z")
    file_handler.puts "</generated_time>"
  
    outer_hash_array.each do |outer_hash|
      file_handler.puts "<group>"
      file_handler.puts "<title>"
      file_handler.puts outer_hash['title']
      file_handler.puts "</title>"
      inner_hash_array = outer_hash['detail']
      title = inner_hash_array[0]
      if title
        inner_hash_array.delete(title)
        inner_hash_array.each do |inner_hash|
          detail_str = sprintf("%-20s", inner_hash['detail1']) + sprintf("%-65s", inner_hash['detail2']) + sprintf("%-30s", inner_hash['detail3'])
          file_handler.puts "<#{title['detail1'].gsub(/\s+/, "_")}>"
          file_handler.puts inner_hash['detail1'].to_s.strip
          file_handler.puts "</#{title['detail1'].gsub(/\s+/, "_")}>"
          file_handler.puts "<#{title['detail2'].gsub(/\s+/, "_")}>"
          file_handler.puts inner_hash['detail2'].to_s.strip
          file_handler.puts "</#{title['detail2'].gsub(/\s+/, "_")}>"
          file_handler.puts "<#{title['detail3'].gsub(/\s+/, "_")}>"
          file_handler.puts inner_hash['detail3'].to_s.strip
          file_handler.puts "</#{title['detail3'].gsub(/\s+/, "_")}>"
        end
      end
      file_handler.puts "</group>"
    end
    file_handler.puts "</mci_report>" 
  end

  def print_json_report(outer_hash_array, report_title)
    report_file_name = report_title.gsub(/\s+/, "_") + ".json"
    File.open(report_file_name,"w") do |f|
      f.write(outer_hash_array.to_json)
    end
  end
end


# Parse the given options and generate the report accordingly
options = Trollop::with_standard_exception_handling trollop_parser do
  raise Trollop::HelpNeeded if ARGV.empty?
  trollop_parser.parse ARGV
end

mr = MciReport.new

if options[:st_id]
  mr.generate_mci_report(options)
elsif options[:st_list_file]
  yaml_contents = YAML.load_file(File.expand_path(options[:st_list_file], __FILE__))
  mr.generate_servertemplate_report(options, yaml_contents)
end

