/*
 * 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.apache.jackrabbit.oak.plugins.memory;

import java.util.Collections;

import javax.annotation.Nonnull;

import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;

import static org.apache.jackrabbit.oak.api.Type.STRING;
import static org.apache.jackrabbit.oak.api.Type.STRINGS;

abstract class EmptyPropertyState implements PropertyState {
    private final String name;

    protected EmptyPropertyState(String name) {
        this.name = name;
    }

    @Nonnull
    @Override
    public String getName() {
        return name;
    }

    @Override
    public boolean isArray() {
        return true;
    }

    @SuppressWarnings("unchecked")
    @Nonnull
    @Override
    public <T> T getValue(Type<T> type) {
        if (type.isArray()) {
            return (T) Collections.emptyList();
        }
        else {
            throw new IllegalStateException("Not a single valued property");
        }
    }

    @Nonnull
    @Override
    public <T> T getValue(Type<T> type, int index) {
        throw new IndexOutOfBoundsException(String.valueOf(index));
    }

    @Override
    public long size() {
        throw new IllegalStateException("Not a single valued property");
    }

    @Override
    public long size(int index) {
        throw new IndexOutOfBoundsException(String.valueOf(index));
    }

    @Override
    public int count() {
        return 0;
    }

    //------------------------------------------------------------< Object >--

    /**
     * Checks whether the given object is equal to this one. Two property
     * states are considered equal if their names and types match and
     * their string representation of their values are equal.
     * Subclasses may override this method with a more efficient
     * equality check if one is available.
     *
     * @param other target of the comparison
     * @return {@code true} if the objects are equal, {@code false} otherwise
     */
    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        else if (other instanceof PropertyState) {
            PropertyState that = (PropertyState) other;
            return getName().equals(that.getName())
                    && isArray() == that.isArray()
                    && getType().equals(that.getType())
                    && getValue(STRINGS).equals(that.getValue(STRINGS));
        }
        else {
            return false;
        }
    }

    /**
     * Returns a hash code that's compatible with how the
     * {@link #equals(Object)} method is implemented. The current
     * implementation simply returns the hash code of the property name
     * since {@link PropertyState} instances are not intended for use as
     * hash keys.
     *
     * @return hash code
     */
    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public String toString() {
        if (isArray()) {
            return getName() + '=' + getValue(STRINGS);
        }
        else {
            return getName() + '=' + getValue(STRING);
        }
    }

}

@@ -915,16 +915,47 @@
 Nonnull;
+%0Aimport javax.jcr.PropertyType;
 %0A%0Aimport
@@ -1040,24 +1040,83 @@
 .api.Type;%0A%0A
+import static org.apache.jackrabbit.oak.api.Type.BINARIES;%0A
 import stati
@@ -3084,39 +3084,37 @@
 er;%0A            
-return 
+if (!
 getName().equals
@@ -3133,59 +3133,138 @@
 e())
-%0A                    && isArray() == that.isArray()
+) %7B%0A                return false;%0A            %7D%0A            if (!getType().equals(that.getType())) %7B%0A                return false;
 %0A   
@@ -3263,32 +3263,35 @@
 lse;%0A           
+ %7D%0A
          && getT
@@ -3283,19 +3283,23 @@
         
-&& 
+   if (
 getType(
@@ -3292,32 +3292,106 @@
   if (getType().
+tag() == PropertyType.BINARY) %7B%0A                return getValue(BINARIES).
 equals(that.getT
@@ -3389,23 +3389,33 @@
 that.get
-Type(
+Value(BINARIES
 ))
+;
 %0A       
@@ -3419,24 +3419,26 @@
         
+%7D%0A
         
 && getVa
@@ -3433,10 +3433,41 @@
     
-&&
+    else %7B%0A                return
  get
@@ -3509,24 +3509,38 @@
 (STRINGS));%0A
+            %7D%0A
         %7D%0A  

Unify PropertyState and CoreValue - correct equality for binaries