#!/usr/bin/env ruby

# -------------------------------------------------------------------------- #
# Copyright 2002-2019, OpenNebula Project, OpenNebula Systems                #
#                                                                            #
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
# not use this file except in compliance with the License. You may obtain    #
# a copy of the License at                                                   #
#                                                                            #
# http://www.apache.org/licenses/LICENSE-2.0                                 #
#                                                                            #
# Unless required by applicable law or agreed to in writing, software        #
# distributed under the License is distributed on an "AS IS" BASIS,          #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
# See the License for the specific language governing permissions and        #
# limitations under the License.                                             #
# -------------------------------------------------------------------------- #

require 'net/http'
require 'uri'
require 'json'
require 'base64'
require 'rexml/document'

# OpenNebula MarketPlace
class OneMarket

    ONE_MARKET_URL = 'https://marketplace.opennebula.systems/'
    AGENT          = 'Market Driver'
    VERSION        = File.dirname(__FILE__) + '/../../VERSION'

    def initialize(url)
        @url   = url || ONE_MARKET_URL
        @agent = "OpenNebula #{File.read(VERSION)} (#{AGENT})"
    end

    def get(path)
        # Get proxy params (needed for ruby 1.9.3)
        http_proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']

        if http_proxy
            # prepend 'http' if missing to parse with URI()
            http_proxy = 'http://' + http_proxy if http_proxy !~ /^http/

            p_uri   = URI(http_proxy)
            p_host  = p_uri.host
            p_port  = p_uri.port
        else
            p_host  = nil
            p_port  = nil
        end

        uri = URI(@url + path)
        req = Net::HTTP::Get.new(uri.request_uri)

        req['User-Agent'] = @agent

        response = Net::HTTP.start(uri.hostname, uri.port, p_host, p_port,
                                   :use_ssl => uri.scheme == 'https') do |http|
            http.request(req)
        end

        return 0, response.body if response.is_a? Net::HTTPSuccess

        [response.code.to_i, response.msg]
    end

    def fetch_appliances
        rc, body = get('/appliance')
        if rc != 0
            return rc, body
        end

        applist = JSON.parse(body)
        appstr  = ''

        applist['appliances'].each do |app|
            id     = app['_id']['$oid']
            source = "#{@url}/appliance/#{id}/download/0"

            tmpl = ''

            app['type'] = 'IMAGE' unless app['type']

            print_var(tmpl, 'NAME',        app['name'])
            print_var(tmpl, 'SOURCE',      source)
            print_var(tmpl, 'IMPORT_ID',   id)
            print_var(tmpl, 'ORIGIN_ID',   '-1')
            print_var(tmpl, 'TYPE',        app['type'])
            print_var(tmpl, 'PUBLISHER',   app['publisher'])
            print_var(tmpl, 'FORMAT',      app['format'])
            print_var(tmpl, 'DESCRIPTION', app['short_description'])
            print_var(tmpl, 'VERSION',     app['version'])
            print_var(tmpl, 'TAGS',        app['tags'].join(', '))
            print_var(tmpl, 'REGTIME',     app['creation_time'])

            if !app['files'].nil? && !app['files'][0].nil?
                file = app['files'][0]
                size = 0

                if file['size'].to_i != 0
                    size = file['size'].to_i / (2**20)
                end

                print_var(tmpl, 'SIZE', size)
                print_var(tmpl, 'MD5',  file['md5'])

                tmpl64 = ''
                print_var(tmpl64, 'DEV_PREFIX', file['dev_prefix'])
                print_var(tmpl64, 'DRIVER',     file['driver'])
                print_var(tmpl64, 'TYPE',       file['type'])

                if !tmpl64.empty?
                    print_var(tmpl,
                              'APPTEMPLATE64',
                              Base64.strict_encode64(tmpl64))
                end
            end

            begin
                if !app['opennebula_template'].nil?
                    vmtmpl64 = template_to_str(
                        JSON.parse(app['opennebula_template'])
                    )
                    print_var(tmpl,
                              'VMTEMPLATE64',
                              Base64.strict_encode64(vmtmpl64))
                end
            rescue StandardError
                nil
            end

            appstr << "APP=\"#{Base64.strict_encode64(tmpl)}\"\n"
        end

        appstr
    end

    private

    def print_var(str, name, val)
        return if val.nil?
        return if val.class == String && val.empty?

        val.gsub!('"', '\"') if val.class == String

        str << "#{name}=\"#{val}\"\n"
    end

    def template_to_str(thash)
        thash.collect do |key, value|
            next if value.nil? || value.empty?

            case value.class.name
            when 'Hash'
                attr = "#{key.to_s.upcase} = [ "

                attr << value.collect do |k, v|
                    next if v.nil? || v.empty?

                    "#{k.to_s.upcase}  =\"#{v}\""
                end.compact.join(',')

                attr << "]\n"
            when 'String'
                "#{key.to_s.upcase} = \"#{value}\""
            end
        end.compact.join("\n")
    end

end

################################################################################
# Main Program. Outpust the list of marketplace appliances
################################################################################

begin
    drv_message = Base64.decode64(ARGV[0])
    doc = REXML::Document.new(drv_message).root
    url = doc.elements['MARKETPLACE/TEMPLATE/ENDPOINT'].text rescue nil
rescue StandardError
    nil
end

# TODO: get marketplace URL from MARKETPLACE Templace for other markets
one_market = OneMarket.new(url)
puts one_market.fetch_appliances
