﻿import { ClockA, ClockB, TimePrinter } from './InterfaceExample.js';

(() => {
	let output: string = "";

	function DisplayLine(text: string): void
	{
		output = output + text + "\n";
	}

	// Interfaces
	let clockA: ClockA = new ClockA();
	let clockB: ClockB = new ClockB(3, 40);
	DisplayLine("Time is " + clockA.GetCurrentTime());

	let timePrinter: TimePrinter;
	timePrinter = new TimePrinter();
	timePrinter.Print(clockA);
	timePrinter.Print(clockB);

	// You can use interfaces to specify optional properties
	interface SquareOptions
	{
		colour?: string;        // ? means optional
		width?: number;
	}

	// Function returns an object literal with colour and area attributes.
	function CreateSquare(options: SquareOptions): { colour: string; area: number; }
	{
		let square: { colour: string; area: number; };
		
		// Create object literal with default values
		square = { colour: "white", area: 100 };

		// Check which optional values have been provided and use them
		if (options.colour) square.colour = options.colour;
		if (options.width) square.area = options.width * options.width;

		return square;
	}

	let square: { colour: string; area: number };

	// If the object literal meets the interface, it doesn't
	// have to explicitly implement it.
	// i.e. the object literals being passed to CreateSquare() all meet the interface
	// SquareOptions above.
	square = CreateSquare({});   // Empty object literal {}
	DisplayLine("Square colour " + square.colour + " area " + square.area);     // default "white" and 100
	square = CreateSquare({ colour: "red" });
	DisplayLine("Square colour " + square.colour + " area " + square.area);     // "red" and 100
	square = CreateSquare({ colour: "blue", width: 5 });
	DisplayLine("Square colour " + square.colour + " area " + square.area);     // "blue" and 25


	// In typescript, interfaces can also contain function signatures
	interface MatchingFunction
	{
		(number1: number, number2: number): boolean
	}

	// Read through an array of numbers checking them one at a time
	// to see if any pass the test.
	function ContainsNumber(num: number, numbers: number[], checkFunction: MatchingFunction): boolean
	{
		for (let i in numbers)
		{
			if (checkFunction(num, numbers[i]) == true)
			{
				return true;
			}
		}
		return false;
	}

	// Simple test, are the numbers equal
	// Must conform to signature in MatchingFunction interface
	function Test(num1: number, num2: number): boolean
	{
		return num1 == num2;
	}

	let matching: boolean = ContainsNumber(2, [1, 2, 3, 4], Test);
	DisplayLine("Array contains the number? " + matching);

	console.log(output);
})();  