/*******************************************************************************
 * Copyright (c) 2014 IBH SYSTEMS GmbH.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBH SYSTEMS GmbH - initial API and implementation
 *******************************************************************************/
package de.dentrassi.osgi.utils;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import org.osgi.framework.Version;
import org.osgi.framework.VersionRange;

public class Filters
{
    public interface Node
    {
    }

    public static class Multi implements Node
    {
        private final String operator;

        private final List<Node> nodes;

        public Multi ( final String operator )
        {
            this.operator = operator;
            this.nodes = new LinkedList<> ();
        }

        private Multi ( final String operator, final List<Node> nodes )
        {
            this.operator = operator;
            this.nodes = nodes;
        }

        public void addNode ( final Node node )
        {
            this.nodes.add ( node );
        }

        @Override
        public String toString ()
        {
            return join ( this.nodes, this.operator );
        }

    }

    public static class Pair implements Node
    {
        private final String key;

        private final String value;

        private final String operator;

        public Pair ( final String key, final String value )
        {
            this.key = key;
            this.value = value;
            this.operator = "=";
        }

        public Pair ( final String key, final String value, final String operator )
        {
            this.key = key;
            this.value = value;
            this.operator = operator;
        }

        public String getKey ()
        {
            return this.key;
        }

        public String getValue ()
        {
            return this.value;
        }

        @Override
        public String toString ()
        {
            return "(" + this.key + this.operator + this.value + ")";
        }

    }

    public static String join ( final List<? extends Node> nodes, final String oper )
    {
        final List<String> s = new LinkedList<> ();
        for ( final Node node : nodes )
        {
            if ( node == null )
            {
                continue;
            }

            final String f = node.toString ();
            if ( !f.isEmpty () )
            {
                s.add ( f );
            }
        }

        if ( s == null || s.isEmpty () )
        {
            return "";
        }

        if ( s.size () == 1 )
        {
            return s.get ( 0 );
        }

        final StringBuilder builder = new StringBuilder ();
        builder.append ( '(' ).append ( oper );

        for ( final String tok : s )
        {
            builder.append ( tok );
        }

        builder.append ( ')' );

        return builder.toString ();
    }

    public static String or ( final List<? extends Node> nodes )
    {
        return join ( nodes, "|" );
    }

    public static String and ( final List<? extends Node> nodes )
    {
        return join ( nodes, "&" );
    }

    public static String and ( final Node... nodes )
    {
        return and ( Arrays.asList ( nodes ) );
    }

    public static String or ( final Node... nodes )
    {
        return or ( Arrays.asList ( nodes ) );
    }

    public static Node pair ( final String key, final String value )
    {
        if ( value == null )
        {
            return null;
        }
        return new Pair ( key, value );
    }

    public static Node pair ( final String key, final String value, final String operator )
    {
        if ( value == null )
        {
            return null;
        }
        return new Pair ( key, value, operator );
    }

    private static String version ( final Version version )
    {
        if ( version == null )
        {
            return null;
        }
        return version.toString ();
    }

    public static Node versionRange ( final String name, final VersionRange versionRange )
    {
        if ( versionRange == null )
        {
            return null;
        }

        final List<Node> nodes = new LinkedList<> ();

        if ( versionRange.getLeft () != null )
        {
            if ( versionRange.getLeftType () == VersionRange.LEFT_OPEN )
            {
                add ( nodes, pair ( name, version ( versionRange.getLeft () ), ">" ) );
            }
            else if ( versionRange.getLeftType () == VersionRange.LEFT_CLOSED )
            {
                add ( nodes, pair ( name, version ( versionRange.getLeft () ), ">=" ) );
            }
        }

        if ( versionRange.getRight () != null )
        {
            if ( versionRange.getRightType () == VersionRange.RIGHT_OPEN )
            {
                add ( nodes, pair ( name, version ( versionRange.getRight () ), "<" ) );
            }
            else if ( versionRange.getRightType () == VersionRange.RIGHT_CLOSED )
            {
                add ( nodes, pair ( name, version ( versionRange.getRight () ), "<=" ) );
            }
        }

        if ( nodes.isEmpty () )
        {
            return null;
        }
        else
        {
            return new Multi ( "&", nodes );
        }
    }

    private static void add ( final List<Node> nodes, final Node node )
    {
        if ( node != null )
        {
            nodes.add ( node );
        }
    }
}

@@ -2309,32 +2309,434 @@
       %7D%0A%0A    %7D%0A%0A
+    public static class Negate implements Node%0A    %7B%0A%0A        private final Node child;%0A%0A        public Negate ( final Node node )%0A        %7B%0A            this.child = node;%0A        %7D%0A%0A        public Node getChild ()%0A        %7B%0A            return this.child;%0A        %7D%0A%0A        @Override%0A        public String toString ()%0A        %7B%0A            return %22(!%22 + this.child.toString() + %22)%22;%0A        %7D%0A%0A    %7D%0A%0A
     public stati
@@ -4467,32 +4467,204 @@
 rator );%0A    %7D%0A%0A
+    public static Node negate ( final Node node )%0A    %7B%0A        if ( node == null )%0A        %7B%0A            return null;%0A        %7D%0A        return new Negate ( node );%0A    %7D%0A%0A
     private stat
@@ -5687,32 +5687,41 @@
     add ( nodes,
+ negate (
  pair ( name, ve
@@ -5761,10 +5761,13 @@
 ), %22
-%3C%22
+%3E=%22 )
  ) )

fix for #128 - use "!(version>=2.0.0)" instead of "version<2.0.0" on R5 OBR version ranges