/*
 * This file is part of CraftoDB, licensed under the MIT License (MIT).
 *
 * Copyright (c) 2017 CraftolutionDE <https://craftolution.de>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Website: https://craftolution.de/
 * Contact: [email protected]
 */
package de.craftolution.craftodb.table;

import de.craftolution.craftodb.column.Column;
import de.craftolution.craftodb.query.Query;
import de.craftolution.craftodb.utils.DBUtil;

import java.util.Arrays;

/**
 * Represents an index
 */
public class Index {

	private final String name;
	private final IndexType type;
	private final String[] columns;

	/** TODO: Documentation */
	public Index(final String name, final IndexType type, final Column... columns) throws IllegalArgumentException {
		DBUtil.notNullNotEmpty(name, "The name must neither be null nor empty!");
		DBUtil.notNull(type, "The type must not be null!");
		DBUtil.notNullNotEmpty(columns, "The columns array must neither be null nor empty!");

		this.name = name;
		this.type = type;
		this.columns = new String[columns.length];

		// Convert Column to String & check for null
		for (int i = 0; i < columns.length; i++) {
			if (columns[i] == null) {
				throw new IllegalArgumentException("The column at index " + i + " is null!");
			}

			this.columns[i] = columns[i].getName();
		}
	}

	/** TODO: Documentation */
	public Index(final String name, final IndexType type, final String... columns) throws IllegalArgumentException {
		DBUtil.notNull(name, "The name must not be null!");
		DBUtil.notNull(type, "The type must not be null!");
		DBUtil.notNullNotEmpty(columns, "The columns array must neither be null nor empty!");

		this.name = name;
		this.type = type;
		this.columns = columns;

		// Check for null
		for (int i = 0; i < columns.length; i++) {
			if (columns[i] == null) {
				throw new IllegalArgumentException("The column at index " + i + " is null!");
			}
		}
	}

	/** TODO: Documentation */
	public String getName() { return this.name; }

	/** TODO: Documentation */
	public IndexType getType() { return this.type; }

	/** TODO: Documentation */
	public String[] getColumns() { return this.columns; }

	/** TODO: Documentation */
	public Query toQuery() {
		final StringBuilder b = new StringBuilder();

		switch (this.type) {
			case FULLTEXT: b.append("FULLTEXT KEY `").append(this.name).append("` (").append(DBUtil.join(c -> "`" + c + "`",  ", ", this.columns)).append(")"); break;
			case INDEX: b.append("KEY `").append(this.name).append("` (").append(DBUtil.join(c -> "`" + c + "`",  ", ", this.columns)).append(")"); break;
			case PRIMARY: b.append("PRIMARY KEY `").append(this.name).append("` (").append(DBUtil.join(c -> "`" + c + "`",  ", ", this.columns)).append(")"); break;
			case UNIQUE: b.append("UNIQUE KEY `").append(this.name).append("` (").append(DBUtil.join(c -> "`" + c + "`",  ", ", this.columns)).append(")"); break;
		}

		return Query.of(b.toString());
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		Index index = (Index) o;

		if (!getName().equals(index.getName())) return false;
		if (getType() != index.getType()) return false;
		// Probably incorrect - comparing Object[] arrays with Arrays.equals
		return Arrays.equals(getColumns(), index.getColumns());
	}

	@Override
	public int hashCode() {
		int result = getName().hashCode();
		result = 31 * result + getType().hashCode();
		result = 31 * result + Arrays.hashCode(getColumns());
		return result;
	}

	@Override
	public String toString() {
		return "Index{" +
				"name='" + name + '\'' +
				", type=" + type +
				", columns=" + Arrays.toString(columns) +
				'}';
	}

}