/**
 * Copyright (C) 2011 Akiban Technologies Inc.
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 */

package com.akiban.ais.model;

import java.util.HashSet;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;

public class GroupIndex extends Index
{
    public static GroupIndex create(AkibanInformationSchema ais, Group group, String indexName, Integer indexId,
                                    Boolean isUnique, String constraint)
    {
        GroupIndex index = new GroupIndex(group, indexName, indexId, isUnique, constraint);
        group.addIndex(index);
        return index;
    }

    public GroupIndex(Group group, String indexName, Integer indexId, Boolean isUnique, String constraint)
    {
        super(new TableName("", group.getName()), indexName, indexId, isUnique, constraint);
        this.group = group;
    }

    @Override
    public Table leafMostTable() {
        assert ! tablesByDepth.isEmpty() : "no tables participate in this group index";
        return tablesByDepth.firstEntry().getValue();
    }

    @Override
    public Table rootMostTable() {
        assert ! tablesByDepth.isEmpty() : "no tables participate in this group index";
        return tablesByDepth.lastEntry().getValue();
    }

    @Override
    public void addColumn(IndexColumn indexColumn) {
        Table indexGenericTable = indexColumn.getColumn().getTable();
        if (!(indexGenericTable instanceof UserTable)) {
            throw new IllegalArgumentException("index column must be of user table: " + indexColumn);
        }
        UserTable indexTable = (UserTable) indexGenericTable;

        super.addColumn(indexColumn);
        GroupIndexHelper.actOnGroupIndexTables(this, indexColumn, GroupIndexHelper.ADD);

        // Add the table into our navigable map if needed. Confirm it's within the branch
        if (participatingTables.add(indexTable)) {
            int indexTableDepth = indexTable.getDepth();
            Map.Entry<Integer,UserTable> rootwardEntry = tablesByDepth.floorEntry(indexTableDepth);
            Map.Entry<Integer,UserTable> leafwardEntry = tablesByDepth.ceilingEntry(indexTableDepth);
            checkIndexTableInBranch(indexColumn, indexTable, indexTableDepth, rootwardEntry, true);
            checkIndexTableInBranch(indexColumn, indexTable, indexTableDepth, leafwardEntry, false);
        }
    }

    private void checkIndexTableInBranch(IndexColumn indexColumn, UserTable indexTable, int indexTableDepth,
            Map.Entry<Integer, UserTable> entry, boolean entryIsRootward)
    {
        if (entry == null) {
            return;
        }
        assert entry.getKey() < indexTableDepth : String.format("failed %d < %d", entry.getKey(), indexTableDepth);
        UserTable entryTable = entry.getValue();

        final UserTable rootward;
        final UserTable leafward;
        if (entryIsRootward) {
            rootward = entryTable;
            leafward = indexTable;
        } else {
            rootward = indexTable;
            leafward = entryTable;
        }

        if (    (entry.getKey().intValue() == indexTableDepth)
                || !leafward.isDescendantOf(rootward))
        {
            throw new IllegalArgumentException(indexColumn + " is not within this group index's branch");
        }
    }

    @Override
    public boolean isTableIndex()
    {
        return false;
    }

    @Override
    public void computeFieldAssociations(Map<Table, Integer> ordinalMap) {
        throw new UnsupportedOperationException("Implement");
        // Probably something like:
        //internalComputeFieldAssociations(ordinalMap, leftMostTable);
    }

    public Group getGroup()
    {
        return group;
    }

    @Override
    public HKey hKey()
    {
        throw new UnsupportedOperationException("Define hkey() on GroupIndex");
    }
    
    @SuppressWarnings("unused")
    private GroupIndex()
    {

    }

    private Group group;
    private final Set<UserTable> participatingTables = new HashSet<UserTable>();
    private final NavigableMap<Integer,UserTable> tablesByDepth = new TreeMap<Integer, UserTable>();
}

@@ -1455,24 +1455,28 @@
 %0A    public 
+User
 Table leafMo
@@ -1661,16 +1661,20 @@
  public 
+User
 Table ro
@@ -4350,77 +4350,36 @@
     
-throw new UnsupportedOperationException(%22Define hkey() on GroupIndex%22
+return leafMostTable().hKey(
 );%0A 

Define hkey for group index table