/*
 * Copyright (c) 2014. Jordan Williams
 *
 * 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.jordanwilliams.heftydb.state;

import com.jordanwilliams.heftydb.table.Table;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Tables implements Iterable<Table> {

    public interface ChangeHandler {
        public void changed();
    }

    private final AtomicLong currentTableId = new AtomicLong();
    private final NavigableMap<Long, Table> tables = new TreeMap<Long, Table>();
    private final ReadWriteLock tableLock = new ReentrantReadWriteLock();
    private final List<ChangeHandler> changeHandlers = new ArrayList<ChangeHandler>();

    public Tables(Collection<Table> initialTables) {
        for (Table table : initialTables){
            tables.put(table.id(), table);
        }

        this.currentTableId.set(tables.isEmpty() ? 0 : tables.lastEntry().getValue().id());
    }

    public synchronized void addChangeHandler(ChangeHandler changeHandler) {
        changeHandlers.add(changeHandler);
    }

    public synchronized void removeChangeHandler(ChangeHandler changeHandler) {
        changeHandlers.remove(changeHandler);
    }

    public long nextId() {
        return currentTableId.incrementAndGet();
    }

    public long currentId() {
        return currentTableId.get();
    }

    public void readLock() {
        tableLock.readLock().lock();
    }

    public void readUnlock() {
        tableLock.readLock().unlock();
    }

    public Table get(long tableId) {
        try {
            tableLock.readLock().lock();
            Table table = tables.get(tableId);
            tableLock.readLock().unlock();
            return table;
        } finally {
            tableLock.readLock().unlock();
        }
    }

    public void add(Table toAdd) {
        try {
            tableLock.writeLock().lock();
            tables.put(toAdd.id(), toAdd);
            notifyChanged();
        } finally {
            tableLock.writeLock().unlock();
        }
    }

    public void removeAll(List<Table> toRemove) {
        try {
            tableLock.writeLock().lock();
            for (Table table : toRemove) {
                tables.remove(table.id());
            }
            notifyChanged();
        } finally {
            tableLock.writeLock().unlock();
        }
    }

    public void remove(Table toRemove) {
        try {
            tableLock.writeLock().lock();
            tables.remove(toRemove.id());
            notifyChanged();
        } finally {
            tableLock.writeLock().unlock();
        }
    }

    public void swap(Table toAdd, Table toRemove) {
        try {
            tableLock.writeLock().lock();
            tables.remove(toRemove.id());
            tables.put(toAdd.id(), toAdd);
            notifyChanged();
        } finally {
            tableLock.writeLock().unlock();
        }
    }

    public int count() {
        return tables.size();
    }

    @Override
    public Iterator<Table> iterator() {
        return tables.values().iterator();
    }

    private synchronized void notifyChanged() {
        for (ChangeHandler changeHandler : changeHandlers) {
            changeHandler.changed();
        }
    }
}

@@ -821,19 +821,19 @@
 avigable
-Map
+Set
 ;%0Aimport
@@ -847,19 +847,19 @@
 til.Tree
-Map
+Set
 ;%0Aimport
@@ -1223,26 +1223,20 @@
 avigable
-Map%3CLong, 
+Set%3C
 Table%3E t
@@ -1255,18 +1255,12 @@
 Tree
-Map%3CLong, 
+Set%3C
 Tabl
@@ -1492,96 +1492,42 @@
     
-for (Table table : initialTables)%7B%0A            tables.put(table.id(), table);%0A        %7D%0A
+this.tables.addAll(initialTables);
 %0A   
@@ -1593,24 +1593,8 @@
 last
-Entry().getValue
 ().i
@@ -2177,296 +2177,8 @@
  %7D%0A%0A
-    public Table get(long tableId) %7B%0A        try %7B%0A            tableLock.readLock().lock();%0A            Table table = tables.get(tableId);%0A            tableLock.readLock().unlock();%0A            return table;%0A        %7D finally %7B%0A            tableLock.readLock().unlock();%0A        %7D%0A    %7D%0A%0A
     
@@ -2283,32 +2283,20 @@
  tables.
-put(toAdd.id(), 
+add(
 toAdd);%0A
@@ -2589,21 +2589,16 @@
 ve(table
-.id()
 );%0A     
@@ -2839,37 +2839,32 @@
 .remove(toRemove
-.id()
 );%0A            n
@@ -3102,21 +3102,16 @@
 toRemove
-.id()
 );%0A     
@@ -3128,24 +3128,12 @@
 les.
-put(toAdd.id(), 
+add(
 toAd
@@ -3388,17 +3388,8 @@
 les.
-values().
 iter
@@ -3565,10 +3565,9 @@
 %7D%0A    %7D%0A
+
 %7D
-%0A

Revert tables changes