//  [go]
func InstallApp(c *gin.Context) {
	appId := c.Param("id")
	var appInfo model.ServerAppList
	m := model.CustomizationPostData{}
	c.BindJSON(&m)

	const CUSTOM = "custom"
	var dockerImage string
	var dockerImageVersion string
	//检查端口
	if len(m.PortMap) > 0 && m.PortMap != "0" {
		//c.JSON(http.StatusOK, model.Result{Success: oasis_err2.INVALID_PARAMS, Message: oasis_err2.GetMsg(oasis_err2.INVALID_PARAMS)})
		portMap, _ := strconv.Atoi(m.PortMap)
		if !port2.IsPortAvailable(portMap, "tcp") {
			c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + m.PortMap})
			return
		}
	}
	//if len(m.Port) == 0 || m.Port == "0" {
	//	m.Port = m.PortMap
	//}

	imageArr := strings.Split(m.Image, ":")
	if len(imageArr) == 2 {
		dockerImage = imageArr[0]
		dockerImageVersion = imageArr[1]
	} else {
		dockerImage = m.Image
		dockerImageVersion = "latest"
	}
	if m.Origin != "custom" {
		appInfo = service.MyService.OAPI().GetServerAppInfo(appId, "")

	} else {

		appInfo.Title = m.Label
		appInfo.Description = m.Description
		appInfo.Icon = m.Icon
		appInfo.ScreenshotLink = model.Strings{}
		appInfo.NetworkModel = m.NetworkModel
		appInfo.Tags = model.Strings{}
		appInfo.Tagline = ""
		appInfo.Index = m.Index

	}

	for _, u := range m.Ports {

		if u.Protocol == "udp" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "tcp" {

			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		} else if u.Protocol == "both" {
			t, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(t, "udp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
			te, _ := strconv.Atoi(u.CommendPort)
			if !port2.IsPortAvailable(te, "tcp") {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.ERROR, Message: "Duplicate port:" + u.CommendPort})
				return
			}
		}

	}
	if m.Origin == "custom" {
		for _, device := range m.Devices {
			if file.CheckNotExist(device.Path) {
				c.JSON(http.StatusOK, model.Result{Success: oasis_err2.DEVICE_NOT_EXIST, Message: device.Path + "," + oasis_err2.GetMsg(oasis_err2.DEVICE_NOT_EXIST)})
				return
			}

		}
	} else {
		dev := []model.PathMap{}
		for _, device := range dev {
			if !file.CheckNotExist(device.Path) {
				dev = append(dev, device)
			}
		}
		m.Devices = dev
	}

	//restart := c.PostForm("restart") //always 总是重启,   unless-stopped 除非用户手动停止容器，否则总是重新启动,    on-failure:仅当容器退出代码非零时重新启动
	//if len(restart) > 0 {
	//
	//}
	//
	//privileged := c.PostForm("privileged") //是否处于特权模式
	//if len(privileged) > 0 {
	//
	//}
	id := uuid.NewV4().String()

	var relyMap = make(map[string]string)
	go func() {
		installLog := model2.AppNotify{}
		installLog.State = 0
		installLog.CustomId = id
		installLog.Message = "installing rely"
		installLog.Type = types.NOTIFY_TYPE_UNIMPORTANT
		installLog.CreatedAt = strconv.FormatInt(time.Now().Unix(), 10)
		installLog.UpdatedAt = strconv.FormatInt(time.Now().Unix(), 10)
		service.MyService.Notify().AddLog(installLog)
		if m.Origin != "custom" {
			for _, plugin := range appInfo.Plugins {
				if plugin == "mysql" {
					mid := uuid.NewV4().String()
					mc := docker_base.MysqlConfig{}
					mc.DataBasePassword = random.RandomString(6, false)
					mc.DataBaseDB = appInfo.Title
					mc.DataBaseUser = "root"
					mc.DataBasePort = "3306"
					mysqlContainerId, err := docker_base.MysqlCreate(mc, mid, m.CpuShares, m.Memory)
					if len(mysqlContainerId) > 0 && err == nil {

						mc.DataBaseHost = mid

						m.Envs = docker_base.MysqlFilter(mc, m.Envs)

						rely := model2.RelyDBModel{}
						rely.Type = types.RELY_TYPE_MYSQL
						rely.ContainerId = mysqlContainerId
						rely.CustomId = mid
						rely.ContainerCustomId = id
						var mysqlConfig model2.MysqlConfigs

						//结构体转换
						copier.Copy(&mysqlConfig, &mc)
						rely.Config = mysqlConfig
						service.MyService.Rely().Create(rely)

						relyMap["mysql"] = mid

					} else {
						docker_base.MysqlDelete(mysqlContainerId)
						installLog.State = 0
						installLog.Message = err.Error()
						service.MyService.Notify().UpdateLog(installLog)
					}
				}
			}
		}

		installLog.Message = "pulling"
		service.MyService.Notify().UpdateLog(installLog)

		// step：下载镜像
		err := service.MyService.Docker().DockerPullImage(dockerImage+":"+dockerImageVersion, installLog)
		if err != nil {
			installLog.State = 0
			installLog.Message = err.Error()
			installLog.Type = types.NOTIFY_TYPE_ERROR
			service.MyService.Notify().UpdateLog(installLog)
			return
		}

		for !service.MyService.Docker().IsExistImage(dockerImage + ":" + dockerImageVersion) {
			time.Sleep(time.Second)
		}

		//if  {

		//}

		//step：创建容器
		// networkName, err := service.MyService.Docker().GetNetWorkNameByNetWorkID(appInfo.NetworkModel)
		// if err != nil {
		// 	//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
		// 	installLog.State = 0
		// 	installLog.Speed = 75
		// 	installLog.Type = types.NOTIFY_TYPE_ERROR
		// 	installLog.Message = err.Error()
		// 	service.MyService.Notify().UpdateLog(installLog)
		// 	return
		// }
		containerId, err := service.MyService.Docker().DockerContainerCreate(dockerImage+":"+dockerImageVersion, id, m, appInfo.NetworkModel)
		installLog.Name = appInfo.Title
		installLog.Icon = appInfo.Icon
		if err != nil {
			//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":80}", 100)
			installLog.State = 0
			installLog.Type = types.NOTIFY_TYPE_ERROR
			installLog.Message = err.Error()
			service.MyService.Notify().UpdateLog(installLog)
			return
		} else {
			//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"starting\",\"speed\":80}", 100)
			installLog.Message = "starting"
			service.MyService.Notify().UpdateLog(installLog)
		}

		//		echo -e "hellow\nworld" >>

		//step：启动容器
		err = service.MyService.Docker().DockerContainerStart(id)
		if err != nil {
			//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":90}", 100)
			installLog.State = 0
			installLog.Type = types.NOTIFY_TYPE_ERROR
			installLog.Message = err.Error()
			service.MyService.Notify().UpdateLog(installLog)
			return
		} else {
			//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"setting upnp\",\"speed\":90}", 100)
			if m.Origin != CUSTOM {
				installLog.Message = "setting upnp"
			} else {
				installLog.Message = "nearing completion"
			}
			service.MyService.Notify().UpdateLog(installLog)
		}

		if m.Origin != CUSTOM {
			//step:启动upnp
			if m.EnableUPNP {
				upnp, err := upnp2.Gateway()
				if err == nil {
					for _, p := range m.Ports {
						if p.Protocol == "udp" {
							upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
							upnp.LocalHost = ip_helper2.GetLoclIp()
							tComment, _ := strconv.Atoi(p.CommendPort)
							upnp.AddPortMapping(tComment, tComment, "UDP")
							time.Sleep(time.Millisecond * 200)
						} else if p.Protocol == "tcp" {
							upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
							upnp.LocalHost = ip_helper2.GetLoclIp()
							tComment, _ := strconv.Atoi(p.CommendPort)
							upnp.AddPortMapping(tComment, tComment, "TCP")
							time.Sleep(time.Millisecond * 200)
						} else if p.Protocol == "both" {

							upnp.CtrlUrl = upnp2.GetCtrlUrl(upnp.GatewayHost, upnp.DeviceDescUrl)
							upnp.LocalHost = ip_helper2.GetLoclIp()
							tComment, _ := strconv.Atoi(p.CommendPort)
							upnp.AddPortMapping(tComment, tComment, "UDP")
							time.Sleep(time.Millisecond * 200)

							upnp.AddPortMapping(tComment, tComment, "TCP")
							time.Sleep(time.Millisecond * 200)
						}

					}

				}
				if err != nil {
					//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":95}", 100)
					installLog.State = 0
					installLog.Type = types.NOTIFY_TYPE_ERROR
					installLog.Message = err.Error()
					service.MyService.Notify().UpdateLog(installLog)
				} else {
					//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"checking\",\"speed\":95}", 100)
					installLog.Message = "checking"
					service.MyService.Notify().UpdateLog(installLog)
				}
			}
		}

		//step: 启动成功     检查容器状态确认启动成功
		container, err := service.MyService.Docker().DockerContainerInfo(id)
		if err != nil && container.ContainerJSONBase.State.Running {
			//service.MyService.Redis().Set(id, "{\"id\"\""+id+"\",\"state\":false,\"message\":\""+err.Error()+"\",\"speed\":100}", 100)
			installLog.State = 0
			installLog.Type = types.NOTIFY_TYPE_ERROR
			installLog.Message = err.Error()
			service.MyService.Notify().UpdateLog(installLog)
			return
		} else {
			//service.MyService.Redis().Set(id, "{\"id\":\""+id+"\",\"state\":true,\"message\":\"installed\",\"speed\":100}", 100)
			installLog.Message = "installed"
			service.MyService.Notify().UpdateLog(installLog)
		}

		rely := model.MapStrings{}

		copier.Copy(&rely, &relyMap)
		// if m.Origin != "custom" {
		// 	for i := 0; i < len(m.Volumes); i++ {
		// 		m.Volumes[i].Path = docker.GetDir(id, m.Volumes[i].Path)
		// 	}
		// }

		portsStr, _ := json2.Marshal(m.Ports)
		envsStr, _ := json2.Marshal(m.Envs)
		volumesStr, _ := json2.Marshal(m.Volumes)
		devicesStr, _ := json2.Marshal(m.Devices)
		//step: 保存数据到数据库
		md := model2.AppListDBModel{
			CustomId: id,
			Title:    appInfo.Title,
			//ScreenshotLink: appInfo.ScreenshotLink,
			Slogan:      appInfo.Tagline,
			Description: appInfo.Description,
			//Tags:           appInfo.Tags,
			Icon:        appInfo.Icon,
			Version:     dockerImageVersion,
			ContainerId: containerId,
			Image:       dockerImage,
			Index:       appInfo.Index,
			//Port:           m.Port,
			PortMap:    m.PortMap,
			Label:      m.Label,
			EnableUPNP: m.EnableUPNP,
			Ports:      string(portsStr),
			Envs:       string(envsStr),
			Volumes:    string(volumesStr),
			Position:   m.Position,
			NetModel:   appInfo.NetworkModel,
			Restart:    m.Restart,
			CpuShares:  m.CpuShares,
			Memory:     m.Memory,
			Devices:    string(devicesStr),
			//Rely:       rely,
			Origin:    m.Origin,
			CreatedAt: strconv.FormatInt(time.Now().Unix(), 10),
			UpdatedAt: strconv.FormatInt(time.Now().Unix(), 10),
		}
		//if appInfo.NetworkModel == "host" {
		//	m.PortMap = m.Port
		//}
		service.MyService.App().SaveContainer(md)
		config.CasaOSGlobalVariables.AppChange = true

	}()

	c.JSON(http.StatusOK, model.Result{Success: oasis_err2.SUCCESS, Message: oasis_err2.GetMsg(oasis_err2.SUCCESS), Data: id})

}