// Path: src/main/java/no/gorman/please/utils/Pair.java
// public class Pair<First, Second> {
//     public final First from;
//     public final Second to;
// 
//     public Pair(First from, Second to) {
//         this.from = from;
//         this.to = to;
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(from, to) + Objects.hash(to, from);
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         return (Objects.equals(from, ((Pair)obj).from ) && Objects.equals(to, ((Pair)obj).to))
//                 || (Objects.equals(from, ((Pair)obj).to ) && Objects.equals(to, ((Pair)obj).from));
//     }
// }


import com.mchange.v2.c3p0.ComboPooledDataSource;
import no.gorman.please.utils.Pair;
import org.jgrapht.alg.DijkstraShortestPath;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleWeightedGraph;
import java.beans.PropertyVetoException;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Stream;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static no.gorman.database.ColumnType.ForeignKey;
import static no.gorman.database.ColumnType.PrimaryKey;
import static no.gorman.database.DatabaseColumns.getPrimaryKey;
import static org.apache.commons.lang.StringUtils.join;
                .filter(where -> where.value != null)
                .map(where -> where.value)
                .collect(toList());
    }

    public static Set<Table> getTables(Class<?> clazz, Where... searchParams) {
        Set<Table> tables = getMappedFields(clazz).stream().map(field -> getColumn(field).getTable()).collect(toSet());

        if (searchParams != null) {
            Stream<Table> tableStream = asList(searchParams).stream()
                    .map(param -> param.column.getTable());
            tables.addAll((Collection<Table>)tableStream.collect(toList()));
        }
        return tables;
    }

    public static List<Field> getMappedFields(Class<?> clazz) {
        List<Field> columnFields = asList(clazz.getDeclaredFields()).stream()
                .filter(f -> f.isAnnotationPresent(Column.class))
                .collect(toList());
        columnFields.forEach(f->f.setAccessible(true));

        if (clazz.getSuperclass() != null) {
            columnFields.addAll(getMappedFields(clazz.getSuperclass()));
        }
        return columnFields;
    }

    public static Collection<Join> findJoins(Collection<Table> tables) {
        Set<Join> joins = new HashSet<>();
// Path: src/main/java/no/gorman/please/utils/Pair.java
// public class Pair<First, Second> {
//     public final First from;
//     public final Second to;
// 
//     public Pair(First from, Second to) {
//         this.from = from;
//         this.to = to;
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(from, to) + Objects.hash(to, from);
//     }
// 
//     @Override
//     public boolean equals(Object obj) {
//         return (Objects.equals(from, ((Pair)obj).from ) && Objects.equals(to, ((Pair)obj).to))
//                 || (Objects.equals(from, ((Pair)obj).to ) && Objects.equals(to, ((Pair)obj).from));
//     }
// }


// Path: src/main/java/no/gorman/database/DBFunctions.java
import com.mchange.v2.c3p0.ComboPooledDataSource;
import no.gorman.please.utils.Pair;
import org.jgrapht.alg.DijkstraShortestPath;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.SimpleWeightedGraph;
import java.beans.PropertyVetoException;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Stream;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static no.gorman.database.ColumnType.ForeignKey;
import static no.gorman.database.ColumnType.PrimaryKey;
import static no.gorman.database.DatabaseColumns.getPrimaryKey;
import static org.apache.commons.lang.StringUtils.join;

                .filter(where -> where.value != null)
                .map(where -> where.value)
                .collect(toList());
    }

    public static Set<Table> getTables(Class<?> clazz, Where... searchParams) {
        Set<Table> tables = getMappedFields(clazz).stream().map(field -> getColumn(field).getTable()).collect(toSet());

        if (searchParams != null) {
            Stream<Table> tableStream = asList(searchParams).stream()
                    .map(param -> param.column.getTable());
            tables.addAll((Collection<Table>)tableStream.collect(toList()));
        }
        return tables;
    }

    public static List<Field> getMappedFields(Class<?> clazz) {
        List<Field> columnFields = asList(clazz.getDeclaredFields()).stream()
                .filter(f -> f.isAnnotationPresent(Column.class))
                .collect(toList());
        columnFields.forEach(f->f.setAccessible(true));

        if (clazz.getSuperclass() != null) {
            columnFields.addAll(getMappedFields(clazz.getSuperclass()));
        }
        return columnFields;
    }

    public static Collection<Join> findJoins(Collection<Table> tables) {
        Set<Join> joins = new HashSet<>();
        Set<Pair<Table, Table>> alreadyTried = new HashSet<>();