class Quest{

	static handler = {
		get(target, prop) {
			if(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(target), prop)?.get){
				return target[prop];
			}
			return target.get(prop);
			
		},
		set(target, prop, value, receiver){
			if(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(target), prop)?.set){
				target[prop] = value;
				return true;
			}
			target.set(prop,value);
			return true;
		}
	};



	id = undefined;
	stage = 0;
	stageHistory = [0];
	state = 0; //0: Not Started, 1: Active, <0 : Failed, >1 : Succeeded

	get active(){
		return (this.state === 1);
	}

	get started(){
		return (this.state !== 0);
	}

	dec(field,v){
		this.inc(field, -1 * v);
	}

	eventExecute(eventId){
		console.log('Quest-Event excuted:',this.passage,eventId);
		$.wiki("<<gs '"+this.passage+"' 'event' '"+eventId+"'>>");
	}

	fail(stage=0){
		this.state = -1;
		if(stage != 0)
			this.setStage(stage);
	}

	func(field: string,...parameter:Array<any>){
		let resultFromPassage = setup.func(this.passage,'func',field,...parameter);
		return resultFromPassage;
	}

	get(field:string,def=undefined){
		if(field in this)
			return this[field];
		if(this.passageExists){
			let resultFromPassage = setup.func(this.passage,'vars',field);
			if(resultFromPassage !== undefined)
				return resultFromPassage
		}
		return def;
	}

	inc(field:string,v=1){
		this.set(field,this.get(field) + v);
	}

	get passage(){
		return 'quest_'+this.id;
	}

	get passageExists(){
		return Story.has(this.passage);
	}

	registerDayEvent(eventId,day,month,year,repeat='none'){
		let t = State.variables.time;
		let data = {
			type: 'questEvent',
			questId: this.id,
			eventId: eventId,
			repeat: repeat
		};
		let key = this.passage + '_' + eventId;
		t.addTimedEvent(key,day,month,year,0,0,1440,data);
	}

	registerEvent(eventId,hour,minute,day,month,year,repeat='none'){
		let t = State.variables.time;
		if(day === undefined || day === null)
			day = t.day;
		if(month === undefined || month === null)
			month = t.month;
		if(year === undefined || year === null)
			year = t.year;

		let data = {
			type: 'questEvent',
			questId: this.id,
			eventId: eventId,
			repeat: repeat
		};
		let key = this.passage + '_' + eventId;
		t.addTimedEvent(key,day,month,year,hour,minute,0,data);
	}

	set(field,v){
		let oldValue = this[field];
		this[field] = v;
		console.log('Update field of quest using set() [questid,field,from,to]',this.id,field,oldValue,v);
	}

	setStage(stage){
		this.stage = stage;
		this.stageHistory.push(stage);
	}

	
	/**
	 * A description of the current stage of the quest.
	 * @readonly
	 * @type {string}
	 */
	get stageDescription(){
		return setup.func(this.passage,'stageDescription',this.stage);
	}

	
	/**
	 * The last stage of the quest that has content.
	 * @readonly
	 * @type {number}
	 */
	get stageEOC(){
		return setup.func(this.passage,'stageEOC') || Infinity;
	}

	start(){
		if(this.passageExists){
			$.wiki("<<gs '"+this.passage+"' 'start'>>");
		}
		this.state = 1;
	}

	succeed(stage=0){
		this.state = 2;
		if(stage != 0)
			this.setStage(stage);
	}

	get title(){
		return setup.func(this.passage,'title');
	}

	constructor(questId=undefined){
		if(questId)
			this.id = questId;
	}

	_init(quest){
		Object.keys(quest).forEach(function (pn) {
			this[pn] = clone(quest[pn]);
		}, this);

		return this;
	}

	clone = function () {
		return (new Quest())._init(this);
	};

	toJSON = function () {
		var ownData = {};
		Object.keys(this).forEach(function (pn) {
			if(typeof this[pn] !== "function")
				ownData[pn] = clone(this[pn]);
		}, this);
		return JSON.reviveWrapper('(new setup.Quest())._init($ReviveData$)', ownData);
	};
}

setup.Quest = Quest;