class RemoteEasydb extends CUI.Element

	initOpts: ->
		super()
		@addOpts
			easydb:
				check:
					idx:
						mandatory: true
						check: "Integer"
					active:
						mandatory: true
						check: Boolean
					url:
						mandatory: true
						check: String
					name:
						check: String
					version:
						check: String
						default: ""
					token:
						check: String
					error:
						check: "PlainObject"
						default: {}

	readOpts: ->
		super()
		@__schema = {}
		@__session = null
		@user_keys = {}
		@__lastError = null
		return

	isFylr: ->
		if CUI.util.isEmpty(@_easydb.version)
			return false
		return parseFloat(@_easydb.version.replace("v","")) >= 6.0

	hasTags: ->
		return @__tags and not CUI.util.isEmpty(@__tags)

	getEasydb4Info: ->
		baseConfig = ez5.session.getBaseConfig("plugin", "easydb-connector-plugin")
		baseConfig = baseConfig.system or baseConfig # TODO: Remove this after #64076 is merged.
		easydb4 = baseConfig.connector_easydb4 or null

		if easydb4
			console.info("Remote easydb '"+@getDisplayname()+"' has easydb 4 configuration: ", easydb4)
		else
			console.warn("Remote easydb '"+@getDisplayname()+"' contains no easydb 4 configuration.")

		return easydb4

	getServerUrl: ->
		@_easydb.url

	getServerToken: ->
		@__session.token

	getSession: ->
		@__session

	getInstance: ->
		@__instance

	addTokenToUrl: (url) ->
		if not url
			return url
		if url.indexOf("?") > -1
			return url + "&access_token=" + @__session.token
		else
			return url + "?access_token=" + @__session.token

	getExportVersionGroups: ->
		Asset.getExportVersionGroups(@__session.getEASConfig())

	getDisplayname: ->
		@_easydb.name
		# ez5.loca.getBestFrontendValue(@__session?.config?.base?.system?.displayname?.value) or
		# 	ez5.loca.getBestFrontendValue(@__session?.config?.base?.system?.name?.value) or
		# 	@getInstance() or
		# 	"<remote>"

	isActive: ->
		@_easydb.active

	isReachable: ->
		!!@__instance

	getLastError: ->
		@__lastError

	load: ->
		dfr = new CUI.Deferred()

		dfr.fail (loca_key, loca_key_attrs = {}) =>
			err = loca_key?.responseJSON # XHR object
			if err
				loca_key_attrs = err.parameters
				loca_key = err.code

			@__instance = null
			if CUI.util.isString(loca_key)
				@__lastError = $$(loca_key, loca_key_attrs)
			else
				@__lastError = $$("remote.easydb.connect.unknown_error")
			return

		dfr.done =>
			@__lastError = null

		if not CUI.util.isEmptyObject(@_easydb.error)
			if @_easydb.error.code
				return dfr.reject(@_easydb.error.code, @_easydb.error.parameters)
			else
				@__lastError = @_easydb.error.msg
				return CUI.rejectedPromise()

		if @_easydb.url.startsWith("https://") or @_easydb.url.startsWith("http://")
			loc = CUI.parseLocation(@_easydb.url)
		else
			loc = null

		if not loc
			console.warn("Remote easydb has an invalid url: ", @_easydb.url)
			dfr.reject("remote.easydb.connect.invalid_url", url: @_easydb.url)
			return dfr.promise()

		@__session = new Session(remoteEasydb: @)

		@__session.get(@_easydb.token) # Get session using an existing token.
		.fail(dfr.reject)
		.done =>
			if @__session.pendingTasks.length > 0
				console.warn("Remote easydb has pending tasks. This is currently not supported.", @_easydb)
				dfr.reject("remote.easydb.connect.pending_tasks")
				return


			if not @__session.hasSystemRight("root", "plugin.easydb-connector-plugin.allow_use_as_server")
				dfr.reject("remote.easydb.connect.no_right_to_use")
				return

			login_event =
				type: "CONNECTOR_LOGIN"
				pollable: false
				info: Connector.getSessionInfoForEvent()

			@__instance = @__session.getInstance().name

			settingsPromise = ez5.api.settings(
				timeout: 15000
				remoteEasydb: @
				handle_error: =>
					return true
			).fail((xhr, status) =>
				@tellProblem(status)
			).done((settings) =>
				@setEasydbVersion(settings.version)
				return
			)

			tagsPromise = ez5.api.tags(
				remoteEasydb: @
				withCredentials: true
			).done (data) =>
				if CUI.util.isEmpty(data)
					return

				for tagGroup in data
					for _tag in tagGroup._tags
						if not _tag.tag?._id
							continue
						_tag.tag._id += "@#{@__instance}"

				@__tags = data
				ez5.tagForm.addTagGroupsFromData(data)
				return

			l10nDeferred = new CUI.Deferred()
			ez5.api.l10n
				remoteEasydb: @
				withCredentials: true
				api: "/user/CURRENT"
			.fail(l10nDeferred.reject)
			.done (data) =>
				ez5.loca.set_user_keys.call(@, 'CURRENT', data)
				EventPoller.saveEvent(login_event, @, true) # ignore errors during this event
				.fail =>
					if @isFylr?()
						# we assume that the connector is not availbale on the remote
						l10nDeferred.reject()
						@__lastError = $$("remote.easydb.connect.remote_connector_not_available")
						return

					@__session.deauthenticate().always =>
						# we assume that the connector is not availbale on the remote
						l10nDeferred.reject()
						@__lastError = $$("remote.easydb.connect.remote_connector_not_available")
						return
				.done =>
					l10nDeferred.resolve()
				return
			l10nPromise = l10nDeferred.promise()

			CUI.whenAllReject(l10nPromise, tagsPromise, settingsPromise).done(dfr.resolve).fail(dfr.reject)
			return

		return dfr.promise()

	logout: ->
		if not @__session?.isAuthenticated()
			return CUI.resolvedPromise()

		info = Connector.getSessionInfoForEvent()

		info.duration = ez5.format_seconds(@__session.getDuration() / 1000)

		logout_event =
			type: "CONNECTOR_LOGOUT"
			pollable: false
			info: info

		dfr = new CUI.Deferred()

		EventPoller.saveEvent(logout_event, @, true) # ignore errors during this event
		.always =>
			if @isFylr?()
				dfr.resolve()
				return
			@__session.deauthenticate()
			.done(dfr.resolve)
			.fail(dfr.reject)

		return dfr.promise()

	loadSchema: ->
		@__schema_inst = new Schema(remoteEasydb: @)
		@__schema = {}
		@__schema_inst.load(null, @__schema, ["CURRENT"], ["mask", "schema"])
		.done =>
			@mask = CURRENT: @__schema.mask.CURRENT
			@schema = CURRENT: @__schema.schema.CURRENT

			ez5.bind_schema_funcs(@schema)

			@setInstanceInMaskAndSchema()
			@schema.enrich_schema(@schema.CURRENT, 'CURRENT')
			@schema.enrich_mask_schema(@mask.CURRENT, 'CURRENT')
			@__schema_inst.initPreferredMask('CURRENT', @__schema)

	get_user_key_CURRENT: (key) ->
		@user_keys.CURRENT?[key]

	setInstanceInMaskAndSchema: ->
		set_ids_in_mask = (mask) =>
			mask._instance = @__instance

			if mask.mask_id
				mask.mask_id = mask.mask_id + '@' + @__instance

			if mask.name
				mask.name = mask.name + '@' + @__instance

			if mask.table_id
				mask.table_id = mask.table_id + '@' + @__instance

			for field in mask.fields
				if field.other_table_id
					field.other_table_id = field.other_table_id + '@' + @__instance

				if field.mask_id and field.mask_id != 'PREFERRED'
					field.mask_id = field.mask_id + '@' + @__instance

				if field.mask
					set_ids_in_mask(field.mask)

		for mask in @mask.CURRENT.masks
			set_ids_in_mask(mask)

		for table in @schema.CURRENT.tables
			table.table_id = table.table_id + '@' + @__instance
			table.name = table.name + '@' + @__instance
			table._instance = @__instance

			for col in table.columns
				if col.other_table_id
					col.other_table_id = col.other_table_id + '@' + @__instance

		return

	setEasydbVersion: (version) ->
		@__easydbVersion = version
		return

	# Using the same code of ez5.coffee
	version: (exp_version) ->
		v = @__easydbVersion
		if v
			v = v.replace(/^v/, "")

		if CUI.util.isEmpty(exp_version)
			return v
		if v == null
			return false

		parts_v = v.split(".").map((v) => parseInt(v))
		parts_exp = exp_version.split(".").map((v) => parseInt(v))

		for part_exp, idx in parts_exp
			if parts_v[idx] > part_exp
				return true
			if part_exp > parts_v[idx]
				return false
		return true
