private const int FILE_BUFFER_LENGTH = 5000000; // ~5MB

        public static DatabaseServer GetDatabaseServer(int serviceId)
        {
            DatabaseServer db = new DatabaseServer();
            ServiceProviderProxy.Init(db, serviceId);
            return db;
        }
        public int InstallWebApplication(InstallationInfo inst)
        {
            // place log record
            TaskManager.StartTask("APP_INSTALLER", "INSTALL_APPLICATION");
            TaskManager.WriteParameter("Virtual directory", inst.VirtualDir);
            TaskManager.WriteParameter("Database group", inst.DatabaseGroup);
            TaskManager.ItemId = inst.PackageId;

            try
            {
                // get application info
                app = GetApplication(inst.PackageId, inst.ApplicationId);

                TaskManager.ItemName = app.Name;

                // check web site for existance
                WebSite webSite = WebServerController.GetWebSite(inst.WebSiteId);

                if (webSite == null)
                    return BusinessErrorCodes.ERROR_WEB_INSTALLER_WEBSITE_NOT_EXISTS;

				TaskManager.WriteParameter("Web site", webSite.Name);

                webSiteName = webSite.Name;
                siteId = webSite.SiteId;

                // change web site properties if required
                if (String.IsNullOrEmpty(inst.VirtualDir))
                {
                    ChangeVirtualDirectoryProperties(webSite, app.WebSettings);
                    WebServerController.UpdateWebSite(webSite);
                }

                // get OS service
                int osId = PackageController.GetPackageServiceId(inst.PackageId, "os");
                os = new OS.OperatingSystem();
                ServiceProviderProxy.Init(os, osId);

                // get remote content path
                contentPath = webSite.ContentPath;

                // create virtual dir if required
                if (!String.IsNullOrEmpty(inst.VirtualDir))
                {
                    // check if the required virtual dir already exists
                    contentPath = Path.Combine(contentPath, inst.VirtualDir);

                    WebVirtualDirectory vdir = null;
                    int result = WebServerController.AddVirtualDirectory(inst.WebSiteId, inst.VirtualDir, contentPath);
                    if (result == BusinessErrorCodes.ERROR_VDIR_ALREADY_EXISTS)
                    {
                        // the directory alredy exists
                        vdir = WebServerController.GetVirtualDirectory(
                            inst.WebSiteId, inst.VirtualDir);

                        contentPath = vdir.ContentPath;
                    }
                    else
                    {
                        vdir = WebServerController.GetVirtualDirectory(
                            inst.WebSiteId, inst.VirtualDir);

                        inst[PROPERTY_VDIR_CREATED] = "True";
                    }

                    // change virtual directory properties if required
                    ChangeVirtualDirectoryProperties(vdir, app.WebSettings);
                    WebServerController.UpdateVirtualDirectory(inst.WebSiteId, vdir);
                }

                // deploy application codebase ZIP and then unpack it
                string codebasePath = app.Codebase;
                string remoteCodebasePath = Path.Combine(contentPath, Path.GetFileName(app.Codebase));

                // make content path absolute
                string absContentPath = FilesController.GetFullPackagePath(inst.PackageId, contentPath);

                // save content path
                inst[PROPERTY_CONTENT_PATH] = contentPath;
                inst[PROPERTY_ABSOLUTE_CONTENT_PATH] = absContentPath;

                // copy ZIP to the target server
                FileStream stream = File.OpenRead(codebasePath);
                int BUFFER_LENGTH = 5000000;

                byte[] buffer = new byte[BUFFER_LENGTH];
                int readBytes = 0;
                while (true)
                {
                    readBytes = stream.Read(buffer, 0, BUFFER_LENGTH);

                    if (readBytes < BUFFER_LENGTH)
                        Array.Resize<byte>(ref buffer, readBytes);

                    FilesController.AppendFileBinaryChunk(inst.PackageId, remoteCodebasePath, buffer);

                    if (readBytes < BUFFER_LENGTH)
                        break;
                }


                
                // unpack codebase
                inst[PROPERTY_INSTALLED_FILES] = String.Join(";",
                   FilesController.UnzipFiles(inst.PackageId, new string[] { remoteCodebasePath }));
                
                // delete codebase zip
                FilesController.DeleteFiles(inst.PackageId, new string[] { remoteCodebasePath });

                // check/create databases
                if (!String.IsNullOrEmpty(inst.DatabaseGroup) &&
                    String.Compare(inst.DatabaseGroup, "None", true) != 0)
                {
                    // database
                    if (inst.DatabaseId == 0)
                    {
                        TaskManager.WriteParameter("Database name", inst.DatabaseName);

                        // we should create a new database
                        SqlDatabase db = new SqlDatabase();
                        db.PackageId = inst.PackageId;
                        db.Name = inst.DatabaseName;
                        inst.DatabaseId = DatabaseServerController.AddSqlDatabase(db, inst.DatabaseGroup);
                        if (inst.DatabaseId < 0)
                        {
                            // rollback installation
                            RollbackInstallation(inst);

                            // return error
                            return inst.DatabaseId; // there was an error when creating database
                        }

                        inst[PROPERTY_DATABASE_CREATED] = "True";
                    }
                    else
                    {
                        // existing database
                        SqlDatabase db = DatabaseServerController.GetSqlDatabase(inst.DatabaseId);
                        inst.DatabaseName = db.Name;

                        TaskManager.WriteParameter("Database name", inst.DatabaseName);
                    }

                    SqlUser user = null;
                    // database user
                    if (inst.UserId == 0)
                    {
                        TaskManager.WriteParameter("Database user", inst.Username);

                        // NEW USER
                        user = new SqlUser();
                        user.PackageId = inst.PackageId;
                        user.Name = inst.Username;
                        user.Databases = new string[] { inst.DatabaseName };
                        user.Password = inst.Password;
                        inst.UserId = DatabaseServerController.AddSqlUser(user, inst.DatabaseGroup);
                        if (inst.UserId < 0)
                        {
                            // rollback installation
                            RollbackInstallation(inst);

                            // return error
                            return inst.UserId; // error while adding user
                        }

                        inst[PROPERTY_USER_CREATED] = "True";
                    }
                    else
                    {
                        // EXISTING USER
                        user = DatabaseServerController.GetSqlUser(inst.UserId);
                        inst.Username = user.Name;

                        TaskManager.WriteParameter("Database user", inst.Username);

                        List<string> databases = new List<string>();
                        databases.AddRange(user.Databases);

                        if (!databases.Contains(inst.DatabaseName))
                        {
                            databases.Add(inst.DatabaseName);

                            user.Databases = databases.ToArray();
                            DatabaseServerController.UpdateSqlUser(user);
                        }
                    }

                    // check connectivity with SQL Server and credentials provided
                    // load user item
                    int sqlServiceId = PackageController.GetPackageServiceId(inst.PackageId, inst.DatabaseGroup);
                    sql = new DatabaseServer();
                    ServiceProviderProxy.Init(sql, sqlServiceId);

                    if (!sql.CheckConnectivity(inst.DatabaseName, inst.Username,
                        inst.Password))
                    {
                        // can't connect to the database
                        RollbackInstallation(inst);

                        return BusinessErrorCodes.ERROR_WEB_INSTALLER_CANT_CONNECT_DATABASE;
                    }

                    // read SQL server settings
                    StringDictionary settings = ServerController.GetServiceSettings(sqlServiceId);
                    serverIpAddressExternal = settings["ExternalAddress"];
					if (settings.ContainsKey("InternalAddress"))
					{
						serverIpAddressInternal = settings["InternalAddress"];
					}
                }

                // ********* RUN INSTALL SCENARIO ***********
                int scriptResult = RunInstallScenario(inst);
                if (scriptResult < 0)
                {
                    // rollback installation
                    RollbackInstallation(inst);

                    // return error
                    return scriptResult;
                }

                // add new installation to the database
                return 0;
            }
            catch (Exception ex)
            {
                // rollback installation
                RollbackInstallation(inst);

                throw TaskManager.WriteError(ex);
            }
            finally
            {
                TaskManager.CompleteTask();
            }
        }