/**
 * Copyright 2013 Cloudera Inc.
 *
 * Licensed 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.kitesdk.data.hbase.avro;

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

import org.apache.avro.Schema;
import org.apache.avro.Schema.Field;

import org.kitesdk.data.ValidationException;
import org.kitesdk.data.spi.FieldPartitioner;
import org.kitesdk.data.PartitionStrategy;
import org.kitesdk.data.hbase.impl.KeySchema;
import org.kitesdk.data.spi.SchemaUtil;

/**
 * A KeySchema implementation powered by Avro.
 */
public class AvroKeySchema extends KeySchema {

  private final Schema schema;

  public AvroKeySchema(Schema entitySchema,
      PartitionStrategy partitionStrategy) {
    super(null, partitionStrategy);
    List<Field> fieldsPartOfKey = new ArrayList<Field>();
    for (FieldPartitioner<?, ?> fieldPartitioner : partitionStrategy.getFieldPartitioners()) {
      Class<?> fieldType = SchemaUtil.getPartitionType(fieldPartitioner, entitySchema);
      Schema fieldSchema;
      if (fieldType == Integer.class) {
        fieldSchema = Schema.create(Schema.Type.INT);
      } else if (fieldType == Long.class) {
        fieldSchema = Schema.create(Schema.Type.LONG);
      } else if (fieldType == String.class) {
        fieldSchema = Schema.create(Schema.Type.STRING);
      } else {
        throw new ValidationException(
            "Cannot encode partition " + fieldPartitioner.getName() +
                " with type " + fieldPartitioner.getSourceType());
      }
      fieldsPartOfKey.add(new Field(fieldPartitioner.getSourceName(), fieldSchema, null, null));
    }
    this.schema = Schema.createRecord(fieldsPartOfKey);
  }

  @Override
  public boolean compatible(KeySchema keySchema) {
    List<FieldPartitioner> fieldPartitioners = getPartitionStrategy()
        .getFieldPartitioners();
    List<FieldPartitioner> otherFieldPartitioners = keySchema
        .getPartitionStrategy().getFieldPartitioners();
    if (fieldPartitioners.size() != otherFieldPartitioners.size()) {
      return false;
    }
    return AvroUtils.avroSchemaTypesEqual(schema, ((AvroKeySchema)keySchema).schema);
  }

  @Override
  public String getRawSchema() {
    return getAvroSchema().toString();
  }

  /**
   * Get the Avro Schema that underlies this KeySchema implementation.
   * 
   * @return The Avro Schema
   */
  public Schema getAvroSchema() {
    return schema;
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((schema == null) ? 0 : schema.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    AvroKeySchema other = (AvroKeySchema) obj;
    if (schema == null) {
      if (other.schema != null)
        return false;
    } else if (!schema.equals(other.schema))
      return false;
    return true;
  }
}

@@ -965,16 +965,80 @@
 emaUtil;
+%0Aimport org.kitesdk.data.spi.partition.IdentityFieldPartitioner;
 %0A%0A/**%0A *
@@ -1440,24 +1440,310 @@
 ioners()) %7B%0A
+      Schema fieldSchema;%0A      if (fieldPartitioner instanceof IdentityFieldPartitioner) %7B%0A        // copy the schema directly from the entity to preserve annotations%0A        fieldSchema = entitySchema%0A            .getField(fieldPartitioner.getSourceName()).schema();%0A      %7D else %7B%0A  
       Class%3C
@@ -1767,16 +1767,29 @@
 hemaUtil
+%0A            
 .getPart
@@ -1837,32 +1837,8 @@
 ;%0A  
-    Schema fieldSchema;%0A
     
@@ -1873,32 +1873,34 @@
 lass) %7B%0A        
+  
 fieldSchema = Sc
@@ -1927,32 +1927,34 @@
 ype.INT);%0A      
+  
 %7D else if (field
@@ -1967,32 +1967,34 @@
 = Long.class) %7B%0A
+  
         fieldSch
@@ -2034,24 +2034,26 @@
 ONG);%0A      
+  
 %7D else if (f
@@ -2072,32 +2072,34 @@
 String.class) %7B%0A
+  
         fieldSch
@@ -2135,24 +2135,26 @@
 pe.STRING);%0A
+  
       %7D else
@@ -2164,16 +2164,18 @@
         
+  
 throw ne
@@ -2197,16 +2197,18 @@
 eption(%0A
+  
         
@@ -2285,16 +2285,18 @@
         
+ 
+ 
 %22 with t
@@ -2335,18 +2335,39 @@
 ceType()
-);
+%0A          );%0A        %7D
 %0A      %7D

Fix key-mapped strings.