#!/usr/bin/ruby

#require 'ruby-debug'
require 'right_cloud_api'
require 'cloud/azure/storage/manager'
require File.expand_path("../../lib/azure_helper",__FILE__)
require 'uri'
require 'yaml'
require 'json'
require 'pp'

include AzureHelper

def deregister_image(accounts, image_name)
    images = registered_images(image_name)
    if images.size == 0
      puts "Found no images matching name or blob"
    else
      puts "Found images to deregister: "
      images.each_with_index do |image, i|
        puts (i+1).to_s + ") Name: " + image['Name']
        puts "Location: " + image['Location']
        puts "Blob: " + image['MediaLink'].to_s if image['MediaLink']
        puts #{i['Name']} #{i['MediaLink'].to_s} #{i['Location']}"
      end
      print "Proceed? [yes|no] "
      proceed = STDIN.gets
      if proceed =~ /^[yY]/
        images.each_with_index do |image, i|
          `azure vm image delete #{image['Name']}`
        end
      end
    end
end

def registered_images(image_name)
  images = JSON.parse(`azure vm image list --json`.chomp)
  registered = []
  image_name = image_name.sub(".vhd","").downcase
  images.each do |i|
#    pp i
    link_name = i["MediaLink"].to_s.dup
    name = i["Name"].dup
    link_name = link_name.sub(".vhd","").downcase
    name = name.sub(".vhd","").downcase
    AZURE_LINUX_LOCATIONS.values.each do |location|
      link_name = link_name.sub(location.sub(" ","-"),"")
      name = name.sub(location.sub(" ","-"),"")
    end
#    p "L #{link_name} IM #{image_name} N #{name}"
    if link_name == image_name or 
       link_name.split("/").last == image_name or
       name == image_name
      registered << i
    end
  end
  return registered
end

def register_image(accounts, container, image_url)
  images = JSON.parse(`azure vm image list --json`)
  accounts.each do |account, api|
    next if account =~ /win$/
    image_name = image_url.split("/").last
    image_name = image_name.sub(".vhd","")
    regional_image_url = "https://#{account}.blob.core.windows.net/#{container}/#{image_name}.vhd"
    name_with_region = image_name + "-" + AZURE_LINUX_LOCATIONS[account].gsub(" ","-")
    image_name_clean = image_name.gsub(/[_-]/," ")

    if registered_images(name_with_region).size > 0
      puts "Image #{name_with_region} already registered"
    else
      begin
        results = api.GetBlobMetadata('Container' => container, 'Blob'=>"#{image_name}.vhd")
        is_public = false
        if api.response.headers.key?("x-ms-meta-rs_public")
          is_public = true
        end
        found_image = true
      rescue
        found_image = false
      end
      if found_image
        unless is_public
          puts "WARNING: Image for region #{account} is not public, registering anyways"
        end
        puts "azure vm image create --label \"#{image_name_clean}\" --os #{OS_TYPE} --blob-url \"#{regional_image_url}\" \"#{name_with_region}\""
        puts `azure vm image create --label \"#{image_name_clean}\" --os #{OS_TYPE} --blob-url \"#{regional_image_url}\" \"#{name_with_region}\"`
      else
        puts "Could not find image #{regional_image_url} for account #{account}"
      end
    end
  end
end

def list_images(accounts, container)
  accounts.each do |account, api|
    results = api.ListBlobs('Container' => container)
    if results['EnumerationResults']['Blobs']
      blobs = results['EnumerationResults']['Blobs']['Blob']
    else
      blobs = []
    end
    if blobs.class == Hash
      blobs = [blobs]
    end
    puts "=================== #{account} ====================="
    blobs.each do |blob|
      name = blob["Name"] 
      # no on-the-fly images
      next if name =~ /os-i-[0-9a-f]{8,12}$/

      ispublic = 'NOT_PUBLISHED'
      results = api.GetBlobMetadata('Container'=>container,"Blob"=>name)
      ispublic = "PUBLISHED" if api.response.headers.key?('x-ms-meta-rs_public')
#      header = header.first if header.respond_to? "first"
#      puts "RES"+results.response.inspect
      puts "NAME #{name} ====== #{ispublic}"
      puts "URL https://#{account}.blob.core.windows.net/#{container}/#{name}"
    end
  end
end

def set_public(accounts, container, image, publicize=true)
  accounts.each do |account, api|
    found_image = false
    begin
      results = api.GetBlobMetadata('Container' => container, 'Blob'=>image)
      is_public = false
      if api.response.headers.key?("x-ms-meta-rs_public")
        is_public = true
      end
      found_image = true
    rescue
      puts "#{account} image #{image} not found"
    end
    #    api_dump(api, "GetBlobProperties", {'Container' => container, 'Blob' => blob})
  #      api_dump(api, "GetBlobMetadata", {'Container' => container, 'Blob' => blob})
    if found_image
      if publicize && !is_public
        timestamp = Time.now.gmtime.to_s
        puts "#{account} ADDING KEY: x-ms-meta-rs_public: #{timestamp}"
        api.SetBlobMetadata('Container' => container, 'Blob' => image, 'Metadata'=>{"rs_public"=>timestamp})
    #    api_dump(api, "SetBlobMetadata", 'Container' => container, 'Blob' => image, 'Metadata'=>{"rs_public"=>timestamp})
      elsif !publicize && is_public
        puts "#{account} REMOVING KEY: x-ms-meta-rs_public: #{timestamp}"
        api.SetBlobMetadata('Container' => container, 'Blob' => image, 'Metadata'=>{})
    #    api_dump(api, "SetBlobMetadata", 'Container' => container, 'Blob' => image, 'Metadata'=>{})
      elsif publicize && is_public
        puts "#{account} image #{image} already public"
      else #!publicize %% !is_public
        puts "#{account} image #{image} for already NOT public"
      end
    end
  end
end

cmd       = ARGV.shift
platform  = ARGV.shift
options   = ARGV.dup
#pp options
unless cmd and cmd != "help"
  puts <<-EOF
USAGE: azure_publish COMMAND [COMMAND OPTIONS]
USAGE: COMMAND set_public <linux|windows> <image_name.vhd>
USAGE: COMMAND unset_public <linux|windows> <image_name.vhd>
USAGE: COMMAND list_images <linux|windows>
USAGE: COMMAND register_image <linux|windows> <image_name.vhd>
USAGE: COMMAND deregister_image <linux|windows> <image_name.vhd|url_to_blob>
EXAMPLE: azure_publish list_images linux
EXAMPLE: azure_publish set_public linux RightImage-CentOS-6.2-x64-v5.8.8.1.vhd
EXAMPLE: azure_publish register_image linux RightImage-CentOS-6.2-x64-v5.8.8.1
EOF
  exit 1
end

if platform == "linux"
  account_names = RS_LINUX_ACCOUNTS
  container = "rightimage-linux"
  OS_TYPE = "linux"
#  (a,p,ep,c,blob) = parse_url(url_src)
elsif platform == "windows"
  account_names = RS_LINUX_ACCOUNTS + RS_WINDOWS_ACCOUNTS
  container = "rightimage-windows"
  OS_TYPE = "windows"
elsif platform == "rswin"
  account_names = RS_LINUX_ACCOUNTS
  container = "rightimage-windows"
  OS_TYPE = "windows"
#  (a,p,ep,c,blob) = parse_url(url_src)
elsif platform == "mswin"
  account_names = RS_WINDOWS_ACCOUNTS
  container = "rightimage-windows"
  OS_TYPE = "windows"
#  (a,p,ep,c,blob) = parse_url(url_src)
end

accounts = account_names.map do |account|
  password = lookup_password(account)
  endpoint = "https://#{account}.blob.core.windows.net"
  [account, RightScale::CloudApi::Azure::Storage::Manager.new(account, password, endpoint, :api_version=>'2012-02-12')]
end

case cmd
when "list_images"  then list_images(accounts, container)
when "set_public"   then set_public(accounts, container, options[0], true)
when "unset_public" then set_public(accounts, container, options[0], false)
when "deregister_image" then deregister_image(accounts, options[0])
when "register_image" then register_image(accounts, container, options[0])
else raise "Unknown cmd #{cmd}"
end


