/*
 * Created on Jan 17, 2013
 * Created by Paul Gardner
 * 
 * Copyright 2013 Azureus Software, Inc.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */


package com.aelitis.azureus.util;

import java.util.Collections;
import java.util.Set;
import java.util.TreeMap;

import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.plugins.PluginInterface;
import org.gudy.azureus2.plugins.utils.FeatureManager;
import org.gudy.azureus2.plugins.utils.FeatureManager.FeatureDetails;
import org.gudy.azureus2.plugins.utils.FeatureManager.Licence;
import org.gudy.azureus2.pluginsimpl.local.PluginInitializer;
import org.gudy.azureus2.pluginsimpl.local.utils.UtilitiesImpl;

import com.aelitis.azureus.core.AzureusCore;
import com.aelitis.azureus.core.AzureusCoreFactory;
import com.aelitis.azureus.core.AzureusCoreRunningListener;

public class 
FeatureUtils 
{
	private static FeatureManager featman;

	static{
		AzureusCoreFactory.addCoreRunningListener(
			new AzureusCoreRunningListener() 
			{
				public void 
				azureusCoreRunning(
					AzureusCore core) 
				{
					PluginInterface pi = core.getPluginManager().getDefaultPluginInterface();
					featman = pi.getUtilities().getFeatureManager();
				}
			});
	}
			
	public static String getMode() {
		boolean isFull = hasFullLicence();
		boolean isTrial = hasFullBurn() && !isFull;
		return isFull ? "plus" : isTrial ? "trial" : "free";
	}
	
	public static boolean hasFullLicence() {
		if (featman == null) {
			//Debug.out("featman null");
			Set<String> featuresInstalled = UtilitiesImpl.getFeaturesInstalled();
			return featuresInstalled.contains("dvdburn");
		}
		licenceDetails fullFeatureDetails = getFullFeatureDetails();
		long now = SystemTime.getCurrentTime();
		return fullFeatureDetails != null && fullFeatureDetails.expiry > now
				&& fullFeatureDetails.displayedExpiry > now;
	}

	public static class licenceDetails {
		public final Licence licence;
		public long expiry;
		public long displayedExpiry;

		public licenceDetails(long expiry, long displayedExpiry, Licence licence) {
			this.expiry = expiry;
			this.displayedExpiry = displayedExpiry;
			this.licence = licence;
		}
		
		public String getRenewalKey() {
			FeatureDetails[] features = licence.getFeatures();
			if (features == null) {
				return null;
			}
			for (FeatureDetails fd : features) {
				Object property = fd.getProperty(FeatureDetails.PR_RENEWAL_KEY);
				if (property instanceof String) {
					return (String) property;
				}
			}
			return null;
		}
	}

	public static licenceDetails getFullFeatureDetails() {
		if (featman == null) {
			Debug.out("featman null");
			return null;
		}

		TreeMap<Long, Object[]> mapOrder = new TreeMap<Long, Object[]>(
				Collections.reverseOrder());
		FeatureDetails[] featureDetails = featman.getFeatureDetails("dvdburn");
		// if any of the feature details are still valid, we have a full
		for (FeatureDetails fd : featureDetails) {
			Licence licence = fd.getLicence();
			int state = licence.getState();
			if (state == Licence.LS_ACTIVATION_DENIED) {
				mapOrder.put(-1L, new Object[] { licence, Long.valueOf(0) });
				continue;
			} else if (state == Licence.LS_CANCELLED) {
				mapOrder.put(-2L, new Object[] { licence, Long.valueOf(0) });
				continue;
			} else if (state == Licence.LS_INVALID_KEY) {
				mapOrder.put(-3L, new Object[] { licence, Long.valueOf(0) });
				continue;
			} else if (state == Licence.LS_REVOKED) {
				mapOrder.put(-4L, new Object[] { licence, Long.valueOf(0) });
				continue;
			} else if (state == Licence.LS_PENDING_AUTHENTICATION) {
				mapOrder.put(-6L, new Object[] { licence, Long.valueOf(0) });
				continue;
			}

			long now = SystemTime.getCurrentTime();
			Long lValidUntil = (Long) fd.getProperty(FeatureDetails.PR_VALID_UNTIL);
			Long lValidOfflineUntil = (Long) fd.getProperty(FeatureDetails.PR_OFFLINE_VALID_UNTIL);

			if (lValidUntil == null && lValidOfflineUntil == null) {
				continue;
			}

			long minValidUntil = -1;
			long maxValidUntil = -1;
			if (lValidUntil != null) {
				minValidUntil = maxValidUntil = lValidUntil.longValue();
				if (minValidUntil < now) {
					mapOrder.put(minValidUntil, new Object[] { licence, Long.valueOf(minValidUntil) });
					continue;
				}
			}
			if (lValidOfflineUntil != null) {
				long validOfflineUntil = lValidOfflineUntil.longValue();
				if (validOfflineUntil < now) {
					mapOrder.put(validOfflineUntil, new Object[] { licence, Long.valueOf(maxValidUntil) });
					continue;
				}
				if (maxValidUntil == -1 || validOfflineUntil > maxValidUntil) {
					maxValidUntil = validOfflineUntil;
				}
			}

			mapOrder.put(maxValidUntil, new Object[] { licence, minValidUntil });
		}

		if (mapOrder.size() == 0) {
			return null;
		}

		Long firstKey = mapOrder.firstKey();
		Object[] objects = mapOrder.get(firstKey);
		Licence licence = (Licence) objects[0];
		return new licenceDetails(firstKey.longValue(), ((Long) objects[1]).longValue(), licence);
	}
	
	public static boolean isTrialLicence(Licence licence) {
		if (featman == null) {
			return false;
		}

		// if any of the FeatureDetails is a trial, return true

		boolean trial = false;
		FeatureDetails[] featureDetails = licence.getFeatures();
		for (FeatureDetails fd : featureDetails) {
			trial = isTrial(fd);
			if (trial) {
				break;
			}
		}

		return trial;
	}

	public static boolean isTrial(FeatureDetails fd) {
		Long lIsTrial = (Long) fd.getProperty(FeatureDetails.PR_IS_TRIAL);
		return lIsTrial == null ? false : lIsTrial.longValue() != 0;
	}
	
	public static long getRemaining() {
		FeatureDetails[] featureDetails = featman.getFeatureDetails("dvdburn_trial");
		if (featureDetails == null) {
			return 0;
		}
		for (FeatureDetails fd : featureDetails) {
			long remainingUses = getRemainingUses(fd);
			if (remainingUses >= 0) {
				return remainingUses;
			}
		}
		return 0;
	}

	private static long getRemainingUses(FeatureDetails fd) {
		if (fd == null) {
			return 0;
		}
		Long lRemainingUses = (Long) fd.getProperty(FeatureDetails.PR_TRIAL_USES_REMAINING);
		long remainingUses = lRemainingUses == null ? -1
				: lRemainingUses.longValue();
		return remainingUses;
	}

	/**
	 * @return
	 */
	public static boolean hasFullBurn() {
		
		PluginInterface pi = PluginInitializer.getDefaultInterface().getPluginState().isInitialisationComplete()
				? AzureusCoreFactory.getSingleton().getPluginManager().getPluginInterfaceByID(
						"azburn_v") : null;
		if (pi == null) {
			// maybe not added yet.. use featman
			Set<String> featuresInstalled = UtilitiesImpl.getFeaturesInstalled();
			return featuresInstalled.contains("dvdburn_trial") && !featuresInstalled.contains("dvdburn");
		}
		return pi.getPluginState().isOperational();
	}
	
	
	public static long getPlusExpiryTimeStamp() {
		licenceDetails fullFeatureDetails = getFullFeatureDetails();
		if (fullFeatureDetails == null || fullFeatureDetails.expiry == 0) {
			return 0;
		}
		return fullFeatureDetails.expiry;
	}

	public static long getPlusExpiryDisplayTimeStamp() {
		licenceDetails fullFeatureDetails = getFullFeatureDetails();
		if (fullFeatureDetails == null || fullFeatureDetails.expiry == 0) {
			return 0;
		}
		return fullFeatureDetails.displayedExpiry;
	}

	public static String getPlusRenewalCode() {
		licenceDetails fullFeatureDetails = getFullFeatureDetails();
		if (fullFeatureDetails == null || fullFeatureDetails.expiry == 0) {
			return null;
		}

		return fullFeatureDetails.getRenewalKey();
	}
}
