/**
 * Copyright 2011 Caleb Richardson
 * 
 * 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 com.outerspacecat.cassandra;

import java.nio.ByteBuffer;
import org.apache.cassandra.thrift.Column;
import org.apache.cassandra.thrift.ColumnOrSuperColumn;
import org.apache.cassandra.thrift.Mutation;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;

/**
 * Defines utility methods for working with Cassandra. Primarily intended to
 * reduce Thrift related boilerplate.
 * 
 * @author Caleb Richardson
 */
public final class Cassandra
{
  private Cassandra ()
  {
  }

  /**
   * Creates a list of mutations based on {@code columns}.
   * 
   * @param columns the columns to update. Must be non {@code null}, all
   *        elements must be non {@code null}, may be empty.
   * @return a list of mutations. Never {@code null}.
   */
  public static ImmutableList<Mutation> mutations ( final Column... columns )
  {
    Preconditions.checkNotNull(columns, "columns required");
    for ( Column column : columns )
      Preconditions.checkNotNull(column, "all columns must be non null");

    ImmutableList.Builder<Mutation> b = ImmutableList.builder();
    for ( Column c : columns )
      b.add(new Mutation().setColumn_or_supercolumn(new ColumnOrSuperColumn().setColumn(c)));
    return b.build();
  }

  /**
   * Creates a composite column name suitable for a mutation. While not suitable
   * for general slicing operations, this function is suitable for an inclusive
   * slice range start.
   * 
   * @param buffers the column names. Must be non {@code null}, all elements
   *        must be non {@code null}, may be empty. Will have their positions
   *        updated.
   * @return a composite column name. Never {@code null}. Will be ready to read
   *         from.
   */
  public static ByteBuffer compositeColumnName ( final ByteBuffer... buffers )
  {
    Preconditions.checkNotNull(buffers, "buffers required");
    for ( ByteBuffer buffer : buffers ) {
      Preconditions.checkNotNull(buffer, "all buffers must be non null");
      Preconditions.checkArgument(buffer.remaining() <= 0xFFFF,
          "buffers must be <= 0xFFFF");
    }

    long length = 0;
    for ( ByteBuffer buffer : buffers ) {
      length += 3 + buffer.remaining();
      if ( length > Integer.MAX_VALUE )
        throw new IllegalArgumentException("combined buffer length too large");
    }

    ByteBuffer ret = ByteBuffer.allocate((int) length);
    for ( ByteBuffer buffer : buffers )
      ret.put((byte) (0xFF & (buffer.remaining() >> 8))).put(
          (byte) (0xFF & buffer.remaining())).put(buffer).put((byte) 0);

    ret.flip();

    return ret;
  }
}
