class ContentDescription {
    public name : string;
    public group : ContentUnit | ContentGroup;
	public description : Say | ((description : ContentDescription, group : ContentUnit | ContentGroup) => Say);
	private saidCount = 0;

    public constructor (name : string, group : ContentUnit | ContentGroup) {
        this.name = name;
        this.group = group;
    }

    public getScore () {
    	return (this.group).getScore();
	}
	
	public getDescription (group : ContentUnit | ContentGroup) : Say {
		this.saidCount++;
		if (typeof this.description == "function") {
		    return this.description(this, group);
        }
		return this.description;
	}

	public setDescription (description : Say | string | ((description : ContentDescription, group : ContentUnit | ContentGroup) => Say) ) {
    	if (!(description instanceof Say)) {
    		this.description = new Say(description);
		} else {
    		this.description = description;
		}
		return this;
	}
	
	public static pickDescriptions (cda : Array<ContentDescription>, target : ContentGroup | ContentUnit) : Array<Say> {
		let a = cda.slice();
		let groups = [];
		for (let i = 0; i < a.length; i++) {
            let randomIndex = Math.floor(Math.random() * (a.length - i)) + i;
            let temp = a[i];
            a[i] = a[randomIndex];
            a[randomIndex] = temp;
        }
		
		// After shuffling the list, descriptions with the highest scores go at the top, and between those the ones with the lowest saidCounts go first
        // If multiple descriptions have the same score/saidCount, they are picked randomly due to the previous shuffling.
        a.sort((a : ContentDescription, b : ContentDescription) => {
            let scoreA = a.getScore() / (a.saidCount + 1);
            let scoreB = b.getScore() / (b.saidCount + 1); // By dividing the score gby the amount of times it was said we increase rotation of descriptions
            if (scoreA != scoreB) return scoreB - scoreA;
            return 0;
        });

		a.forEach(description => {
			groups.push(description.group);
		});

        let matches = (<any> target).matchAgainst(<any> groups);
        if (matches != undefined) {
			let result = [];
			matches.forEach(i => {
				result.push(a[i].getDescription(target));
				result.push(new Say(" "));
			});
			return result;
		} else {
        	console.warn("No description available for", target);
        	return [new Say("Warning: No description available for the current situation. Please report so it can be corrected.")];
		}
	}
}