//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
// 
using System;
using System.Diagnostics;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.IO;

namespace LicenseTimeBombClass
{
	/// <summary>
	/// Podsumowanie dla TimeBombLicenseProvider.
	/// </summary>
	public class TimeBombLicenseProvider : LicenseProvider
	{
		protected virtual bool IsKeyValid(string key, Type type) 
		{
			// Jeśli ciąg nie jest pusty
			if (key != null) 
			{
				DateTime now = DateTime.Now;
				// Uzyskanie liczby procesorów, dla których jest ważna licencja.
				int startIndex = key.IndexOf(',') + 1;
				int endIndex = key.IndexOf(',', startIndex) + 1;
				DateTime validStartTime = new DateTime(Convert.ToInt64(key.Substring(startIndex, endIndex - startIndex - 1)));
				DateTime validEndTime = new DateTime(Int64.Parse(key.Substring(endIndex)));
				
				Debug.WriteLine("Data początkowa: " + validStartTime.ToString() + " Data końcowa: " + validEndTime.ToString() + "\n" + "Teraz: " + now.ToString());

				Debug.WriteLine(string.Format("Obecna data jest późniejsza niż data początkowa: {0}", now > validStartTime));
				Debug.WriteLine(string.Format("Obecna data jest wcześniejsza niż data końcowa: {0}", now < validEndTime));
				// Potwierdzenie ciągu licencji i liczby procesorów.
				return (now > validStartTime && now < validEndTime && key.StartsWith(string.Format("{0} jest licencjonowanym komponentem.",type.FullName)));
			}
			return false;
		}

		public override License GetLicense(LicenseContext context, Type type, object instance, bool allowExceptions) 
		{
			TimeBombLicense lic = null;
            
			Debug.Assert(context != null, "No context provided!");
			// Żadna operacja nie jest wykonywana, jeśli nie podano kontekstu.
			if (context != null) 
			{
				// Jeśli ten element sterujący znajduje się w trybie runtime
				if (context.UsageMode == LicenseUsageMode.Runtime) 
				{
					// Uzyskanie zapisanego klucza licencji
					string key = context.GetSavedLicenseKey(type, null);

					// Sprawdzenie, czy zapisany klucz licencji nie jest pusty
					// i wywołanie IsKeyValid w celu upewnienia się,
                    // czy klucz licencji jest ważny.
					if (key != null && IsKeyValid(key, type)) 
					{
						// Jeśli klucz jest ważny, należy utworzyć nową licencję.
						lic = new TimeBombLicense(this, key);
					}
				}

				// W trybie projektu lub w przypadku nieodnalezienia klucza
				// licencji w kontekście runtime należy podjąć próbę
				// wyszukania pliku .LIC.
				if (lic == null) 
				{
					// Utworzenie ścieżki do pliku .LIC
					string modulePath = null;

					// Próba odnalezienia pliku dla podzespołu.
					if (context != null) 
					{
						ITypeResolutionService resolver = (ITypeResolutionService)context.GetService(typeof(ITypeResolutionService));
						if (resolver != null)
							modulePath = resolver.GetPathOfAssembly(type.Assembly.GetName());
					}


					if (modulePath == null)
						modulePath = type.Module.FullyQualifiedName;

					// Uzyskanie ścieżki z położenia pliku
					string moduleDir = Path.GetDirectoryName(modulePath);
					
					// Utworzenie ścieżki pliku .LIC.
					string licenseFile = moduleDir + "\\" + type.FullName + ".lic";

					Debug.WriteLine("Path of license file: " + licenseFile);

					// Jeśli plik .LIC istnieje, należy go zbadać
					if (File.Exists(licenseFile)) 
					{
						// Odczyt pierwszego wiersza
						Stream licStream = new FileStream(licenseFile, FileMode.Open, FileAccess.Read, FileShare.Read);
						StreamReader sr = new StreamReader(licStream);
						string s = sr.ReadLine();
						sr.Close();

						Debug.WriteLine("Zawartość pliku licencji: " + s);

						// Sprawdzenie, czy klucz jest ważny.
						if (IsKeyValid(s, type)) 
						{
							// Klucz jest ważny, a więc można utworzyć nową licencję.
							lic = new TimeBombLicense(this, s);
						}
					}

					// Jeśli udało się utworzyć licencję, to należy umieścić ją w kontekście.
					if (lic != null) 
					{
						context.SetSavedLicenseKey(type, lic.LicenseKey);
					}
				}

			}
			return lic;
		}
		public class TimeBombLicense : License 
		{
			private TimeBombLicenseProvider owner;
			private string key;
			private DateTime validStartTime;
			private DateTime validEndTime;

			public TimeBombLicense(TimeBombLicenseProvider owner, string key) 
			{
				this.owner = owner;
				this.key = key;
				int startIndex = key.IndexOf(',') + 1;
				int endIndex = key.IndexOf(',', startIndex) + 1;
				this.validStartTime = new DateTime(Convert.ToInt64(key.Substring(startIndex, endIndex - startIndex - 1)));
				this.validEndTime = new DateTime(Int64.Parse(key.Substring(endIndex)));
			}
			public override string LicenseKey 
			{ 
				get 
				{
					return key;
				}
			}

			public DateTime ValidStartTime 
			{
				get 
				{
					return validStartTime;
				}
			}
			public DateTime ValidEndTime 
			{
				get 
				{
					return validEndTime;
				}
			}

			public override void Dispose() 
			{
			}
		}
	}
}
