using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;

/* ここから追加 */
using Microsoft.WindowsAzure.StorageClient; // CloudDriveの利用に必要
using System.Net;                           // DNSアクセスに利用
using System.Diagnostics;                   // Processクラスの利用に必要
/* ここまで追加 */

namespace WebRole1
{
    public class WebRole : RoleEntryPoint
    {
        /* ここから追加 */
        private CloudDrive drive;
        /* ここまで追加 */

        public override bool OnStart()
        {
            // 構成の変更を処理する方法については、
            // MSDN トピック (http://go.microsoft.com/fwlink/?LinkId=166357) を参照してください。

            /* ここから追加 */
            //
            // Webロールのプロパティから文字列を読み出す
            //
            CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
            {
                configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
                RoleEnvironment.Changed += (sender, arg) =>
                {
                    if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
                        .Any((change) => (change.ConfigurationSettingName == configName)))
                    {
                        if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
                        {
                            RoleEnvironment.RequestRecycle();
                        }
                    }
                };
            });

            //
            // Windows Azure Drive用のblob割り当て
            //
            int DRIVE_SIZE = 1024; // ドライブのサイズは1024MB（=1GB）とする

            // Webロールのプロパティで「StorageAccount」として設定しておいたアカウント情報を読み出す
            CloudStorageAccount account = CloudStorageAccount.FromConfigurationSetting("StorageAccount");

            // blob操作用のクライアントを作成
            CloudBlobClient client = account.CreateCloudBlobClient();

            // ストレージコンテナを作成
            CloudBlobContainer container = client.GetContainerReference("ftp-storage");

            // 成功するまでリトライする
            bool is_created = false;
            while (!is_created)
            {
                try
                {
                    container.CreateIfNotExist();
                    is_created = true;
                }
                catch (StorageClientException e)
                {
                    // エラーコードをチェックしてサービス側のエラーであればリトライする
                    switch (e.ErrorCode)
                    {
                        case StorageErrorCode.ServiceInternalError:
                        case StorageErrorCode.ServiceTimeout:
                        case StorageErrorCode.ServiceBadResponse:
                        case StorageErrorCode.ServiceIntegrityCheckFailed:
                        case StorageErrorCode.TransportError:
                            break;
                        case StorageErrorCode.ContainerAlreadyExists:
                            is_created = true;
                            break;
                        // そのほかのエラーはとりあえず放置
                        default:
                            is_created = true;
                            break;
                    }
                }
            }
            
            // blobの参照を取得
            CloudPageBlob blob = container.GetPageBlobReference("storageblob");

            // ローカルストレージを取得
            LocalResource localCache = RoleEnvironment.GetLocalResource("DriveCache01");

            // キャッシュとして利用するパスと容量を指定
            int cacheSize = localCache.MaximumSizeInMegabytes;
            CloudDrive.InitializeCache(localCache.RootPath, cacheSize);

            // AzureDriveの作成
            drive = new CloudDrive(blob.Uri, account.Credentials);
            string drive_path = "";
            try
            {
                // ドライブを作成
                // CloudPageBlob側でcreateを実行してしまうとエラーとなるので注意
                drive.CreateIfNotExist(DRIVE_SIZE);
                // ドライブをマウント
                drive_path = drive.Mount(cacheSize, DriveMountOptions.None);
                // adrive_pathは末尾に「\」がついているのでこれを除く
                drive_path = drive_path.Replace(@"\", "");
            }
            catch (CloudDriveException)
            {
                return base.OnStart();
            }

            //
            // インターネット側のIPアドレスを取得
            //
            string dep_id = RoleEnvironment.DeploymentId;
            string hostname = dep_id + @".cloudapp.net"; // stagingの場合、ホスト名はこれになる
            string ip_addr;
            try
            {
                IPHostEntry ip_info = Dns.GetHostEntry(hostname);
                ip_addr = ip_info.AddressList[0].ToString();
            }
            catch (System.Net.Sockets.SocketException)
            {
                ip_addr = "";
            }
            if (ip_addr == "") // productionの場合、作成時に指定したDNSプレフィックスが付加される
            {
                try
                {
                    hostname = "＜プレフィックス＞" + ".cloudapp.net";
                    IPHostEntry ip_info = Dns.GetHostEntry(hostname);
                    ip_addr = ip_info.AddressList[0].ToString();
                }
                catch (System.Net.Sockets.SocketException) // それでも失敗したらlocalhostを指定
                {
                    hostname = "localhost";
                    ip_addr = "127.0.0.1";
                }
            }
            if (RoleEnvironment.IsEmulated)
            {
                hostname = "localhost";
                ip_addr = "127.0.0.1";
            }

            // onstart.cmdを実行
            Process p = new Process();
            string role_root = Environment.GetEnvironmentVariable("ROLEROOT");
            p.StartInfo.FileName = @"cmd.exe";
            p.StartInfo.Arguments = @"/c """"" + role_root + @"\approot\bin\onstart.cmd""""";
            p.StartInfo.UseShellExecute = false;

            // 環境変数を定義
            p.StartInfo.EnvironmentVariables.Add("INET_IP_ADDR", ip_addr);

            if (RoleEnvironment.IsEmulated)
            {
                // エミュレータ環境の場合
                p.StartInfo.EnvironmentVariables.Add("AZUREDRIVE_ROOT", @"C:\temp");
            }
            else
            {
                // 実環境の場合
                p.StartInfo.EnvironmentVariables.Add("AZUREDRIVE_ROOT", drive_path);
            }
            
            // 下記に使用するSSL証明書のハッシュを指定
            string ssl_cert = "";
            p.StartInfo.EnvironmentVariables.Add("SSL_CERT", ssl_cert);

            // 実行
            p.Start();
            /* ここまで追加 */

            return base.OnStart();
        }

        /* ここから追加 */
        public override void OnStop()
        {
            try
            {
                drive.Unmount();
            }
            catch (CloudDriveException) { }
  
            base.OnStop();
        }
    /* ここまで追加 */
    }
}
