/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.cauldron.bld.obr;

import java.util.ArrayList;
import java.util.List;

import org.cauldron.sigil.model.common.LDAPExpr;
import org.cauldron.sigil.model.common.LDAPParseException;
import org.cauldron.sigil.model.common.LDAPParser;
import org.cauldron.sigil.model.common.Not;
import org.cauldron.sigil.model.common.Ops;
import org.cauldron.sigil.model.common.SimpleTerm;
import org.cauldron.sigil.model.common.VersionRange;
import org.osgi.framework.Version;

class VersionRangeHelper {
	
	// e.g. (&(version>=1.0.0)(version<=2.0.0)) (&(version>1.0.0)(version<2.0.0)) (&(!(version<1.0.0))(!(version>2.0.0))) (&(!(version<=1.0.0))(!(version>=2.0.0))) (version=1.0.0) (version>=1.0.0) (version<=2.0.0) (version>1.0.0) (version<2.0.0)  (!(version>2.0.0)) (!(version<1.0.0)) (!(version>=2.0.0)) (!(version<=1.0.0))
	public static void main(String[] args) throws LDAPParseException {
		for ( String arg : args ) {
			LDAPExpr expr = LDAPParser.parseExpression(arg.trim());
			System.out.println( expr + " -> " + decodeVersions(expr) ); 
		}
	}
	
	static VersionRange decodeVersions(LDAPExpr expr) throws NumberFormatException {
		ArrayList<LDAPExpr> terms = new ArrayList<LDAPExpr>(1);
		
		findExpr("version", expr, terms);
		
		if ( terms.isEmpty() ) {
			// woo hoo!
			return VersionRange.ANY_VERSION;
		}
		else {
			switch ( terms.size() ) {
			case 1: {
				return parseSimpleVersionRange(terms.get(0));
			}
			case 2: {
				return parseCompoundVersionRange(terms.get(0), terms.get(1));
			}
			default: {
				// (&(version>=min)(!(version=min))(version<=max)(!(version=max))) 	- (min,max) - not dealt with!!
				// (&(|(version>min)(version=min))(|(version<max)(version=max))) 	- [min,max] - not dealt with!!
				throw new NumberFormatException("Failed to parse complicated version expression " + expr);				
			}
			}
		}
	}

	// (&(version>=min)(version<=max)) 									- [min,max]
	// (&(version>min)(version<max))									- (min,max)
	//
	// (&(!(version<min))(!(version>max)))								- [min,max]
	// (&(!(version<=min))(!(version>=max)) 							- (min,max)
	private static VersionRange parseCompoundVersionRange(LDAPExpr left, LDAPExpr right) throws NumberFormatException {
		VersionRange one = parseSimpleVersionRange(left);
		VersionRange two = parseSimpleVersionRange(right);
		
		// sanity check
		if ( one.isPointVersion() || two.isPointVersion() ) {
			throw new NumberFormatException("Unexpected point version in compound expression " + left);				
		}
		
		VersionRange max = one.getFloor().equals( Version.emptyVersion ) ? one : two;
		VersionRange min = max == one ? two : one;

		return new VersionRange( min.isOpenFloor(), min.getFloor(), max.getCeiling(), max.isOpenCeiling() );
	}

	// possible variations				
	// (version=v)														- [v,v]
	//
	// (version>=min)													- [min,*)
	// (version<=max)													- [0,max]
	//
	// (version>min)													- (min,*)
	// (version<max)													- [0,max)
	//
	// (!(version>max))													- [0,max]
	// (!(version<min))													- [min,*)
	// (!(version>=max))												- [0,max)
	// (!(version<=min))												- (0,*)
	private static VersionRange parseSimpleVersionRange(LDAPExpr expr) throws NumberFormatException {
		Version min = Version.emptyVersion;
		Version max = VersionRange.INFINITE_VERSION;
		boolean openFloor = false;
		boolean openCeiling = false;
		if ( expr instanceof Not ) {
			Not n = (Not) expr;
			SimpleTerm t = (SimpleTerm) n.getEx();
			if ( t.getOp() == Ops.EQ ) {
				throw new NumberFormatException("Unexpected point version in negated expression " + expr);								
			}
			if ( !isMax(t.getOp()) ) {
				max = toVersion(t);
				openCeiling = !openFloor(t);
			}
			else if ( !isMin(t.getOp()) ) {
				min = toVersion(t);
				openFloor = !openCeiling(t);
			}
			else {
				throw new IllegalStateException("Unexpected operator " + t.getOp());
			}
		}
		else {
			SimpleTerm t = (SimpleTerm) expr;
			if ( t.getOp().equals( Ops.EQ ) ) {
				max = toVersion(t);
				min = max;
				openFloor = false;
				openCeiling = false;
			}
			else if ( isMax(t.getOp()) ) {
				max = toVersion(t); 
				openCeiling = openCeiling(t);
			}
			else if ( isMin(t.getOp()) ) {
				min = toVersion(t);
				openFloor = openFloor(t);
			}
			else {
				throw new IllegalStateException("Unexpected operator " + t.getOp());
			}
		}

		return new VersionRange( openFloor, min, max, openCeiling );
	}

	private static Version toVersion(SimpleTerm t) {
		return new Version(t.getRval());
	}

	private static boolean isMax(Ops op) {
		return op == Ops.LE || op == Ops.LT;
	}
	
	private static boolean isMin(Ops op) {
		return op == Ops.GE || op == Ops.GT;
	}

	private static boolean openFloor(SimpleTerm t) {
		return t.getOp() == Ops.GT;
	}

	private static boolean openCeiling(SimpleTerm t) {
		return t.getOp() == Ops.LT;
	}
	
	private static void findExpr(String string, LDAPExpr expr, List<LDAPExpr> terms) {
		if ( expr instanceof SimpleTerm ) {
			SimpleTerm term = (SimpleTerm) expr;
			if ( term.getName().equals(string) ) {
				terms.add(term);
			}
		}
		else if ( expr instanceof Not ) {
			Not not = (Not) expr;
			if ( not.getEx() instanceof SimpleTerm ) {
				SimpleTerm term = (SimpleTerm) not.getEx();
				if ( term.getName().equals(string) ) {
					terms.add(not);
				}
			}
		}
		else {
			for ( LDAPExpr c : expr.getChildren() ) {
				findExpr(string, c, terms);
			}
		}
	}
}
