/*******************************************************************************
* Copyright (c) 2014 Open Door Logistics (www.opendoorlogistics.com)
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v3
* which accompanies this distribution, and is available at http://www.gnu.org/licenses/lgpl.txt
******************************************************************************/
package com.opendoorlogistics.core.tables.utils;
import com.opendoorlogistics.api.tables.ODLDatastore;
import com.opendoorlogistics.api.tables.ODLTableDefinition;
import com.opendoorlogistics.api.tables.ODLTableReadOnly;
import com.opendoorlogistics.api.tables.TableFlags;
import com.opendoorlogistics.core.tables.ColumnValueProcessor;
import com.opendoorlogistics.core.utils.NullComparer;
final public class DatastoreComparer {
public static long CHECK_COLUMN_FLAGS = 1<<0;
public static long CHECK_IMMUTABLE_TABLE_IDS = 1<<1;
public static long CHECK_IMMUTABLE_COLUMN_IDS = 1<<2;
public static long CHECK_IMMUTABLE_COLUMN_ROW_IDS = 1<<3;
public static long CHECK_TABLE_NAME = 1<<4;
public static long ALLOW_EXTRA_COLUMNS_ON_SECOND_TABLE = 1<<5;
public static long CHECK_ALL = CHECK_COLUMN_FLAGS|CHECK_IMMUTABLE_TABLE_IDS|CHECK_IMMUTABLE_COLUMN_IDS|CHECK_IMMUTABLE_COLUMN_ROW_IDS|CHECK_TABLE_NAME;
public static long CHECK_ROW_SELECTION_STATE = 1<<6;
public static boolean isSameStructure(ODLDatastore<? extends ODLTableDefinition> a, ODLDatastore<? extends ODLTableDefinition> b) {
return isSameStructure(a, b, CHECK_ALL);
}
/**
* Check if datastores have the same structure. If both are null, the method returns true.
* @param a
* @param b
* @param checkColumnFlags
* @return
*/
public static boolean isSameStructure(ODLDatastore<? extends ODLTableDefinition> a, ODLDatastore<? extends ODLTableDefinition> b, long flags) {
if(a==null && b==null){
return true;
}
if( (a!=null && b==null) || (a==null && b!=null)){
return false;
}
if (a.getTableCount() != b.getTableCount()) {
return false;
}
if (a.getFlags() != b.getFlags()) {
return false;
}
for (int i = 0; i < a.getTableCount(); i++) {
ODLTableDefinition ta = a.getTableAt(i);
// retrieve by table name as table id changing isn't a structural difference by name is...
ODLTableDefinition tb = TableUtils.findTable(b, ta.getName());
if(tb==null){
return false;
}
if(hasFlag(flags, CHECK_IMMUTABLE_TABLE_IDS)){
if(ta.getImmutableId()!=tb.getImmutableId()){
return false;
}
}
if (!isSameStructure(ta, ta, flags)) {
return false;
}
}
return true;
}
public static boolean isSame(ODLDatastore<? extends ODLTableReadOnly> a, ODLDatastore<? extends ODLTableReadOnly> b, long flags) {
if(NullComparer.compare(a, b)!=0){
return false;
}
if (!isSameStructure(a, b,flags)) {
return false;
}
for (int i = 0; i < a.getTableCount(); i++) {
ODLTableReadOnly ta = a.getTableAt(i);
ODLTableReadOnly tb = TableUtils.findTable(b, ta.getName());
if(!isSame(ta, tb,flags)){
return false;
}
}
return true;
}
public static boolean isSame(ODLTableReadOnly ta, ODLTableReadOnly tb, long flags) {
if(!isSameStructure(ta, tb, flags)){
return false;
}
if(hasFlag(flags, CHECK_IMMUTABLE_TABLE_IDS)){
if (ta.getImmutableId() != tb.getImmutableId()) {
return false;
}
}
if (ta.getRowCount() != tb.getRowCount()) {
return false;
}
int rows = ta.getRowCount();
int cols = ta.getColumnCount();
for (int row = 0; row < rows; row++) {
if(hasFlag(flags, CHECK_IMMUTABLE_COLUMN_ROW_IDS)){
if(ta.getRowId(row)!=tb.getRowId(row)){
return false;
}
}
// check selection state if needed
if(hasFlag(flags, CHECK_ROW_SELECTION_STATE)){
long aRowId = ta.getRowId(row);
long bRowId = tb.getRowId(row);
if(aRowId!=-1 && bRowId!=-1){
boolean aSel = hasFlag(ta.getRowFlags(aRowId), TableFlags.FLAG_ROW_SELECTED_IN_MAP);
boolean bSel = hasFlag(tb.getRowFlags(bRowId), TableFlags.FLAG_ROW_SELECTED_IN_MAP);
if(aSel!=bSel){
return false;
}
}
}
for(int col = 0 ; col < cols; col++){
if(!ColumnValueProcessor.isEqualSameType(ta.getColumnType(col), ta.getValueAt(row, col), tb.getValueAt(row, col))){
return false;
}
}
}
return true;
}
/**
* Check if tables have the same structure. If both are null, the method returns true.
* @param a
* @param b
* @param flags
* @return
*/
public static boolean isSameStructure(ODLTableDefinition a, ODLTableDefinition b,long flags) {
if(a==null && b==null){
return true;
}
if( (a!=null && b==null) || (a==null && b!=null)){
return false;
}
// table name changes are considered a structurally change
if( ((flags & CHECK_TABLE_NAME) == CHECK_TABLE_NAME) && a.getName().equals(b.getName())==false){
return false;
}
int nc = a.getColumnCount();
if(hasFlag(flags, ALLOW_EXTRA_COLUMNS_ON_SECOND_TABLE)){
if(b.getColumnCount()< nc){
return false;
}
}else{
if (nc != b.getColumnCount()) {
return false;
}
}
for (int col = 0; col < nc; col++) {
if (a.getColumnName(col).equals(b.getColumnName(col)) == false || a.getColumnType(col) != b.getColumnType(col)) {
return false;
}
if (hasFlag(flags, CHECK_COLUMN_FLAGS) && a.getColumnFlags(col) != b.getColumnFlags(col)) {
return false;
}
}
return true;
}
private static boolean hasFlag(long flags, long flagToCheckFor){
return (flags & flagToCheckFor)==flagToCheckFor;
}
}