<commit_before>/*
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * 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 Lesser General Public License for more details.
 *
 * Copyright (c) 2009 Pentaho Corporation..  All rights reserved.
 */
package org.pentaho.agilebi.modeler;

import org.pentaho.agilebi.modeler.geo.GeoContext;
import org.pentaho.agilebi.modeler.nodes.*;
import org.pentaho.agilebi.modeler.nodes.annotations.GeoAnnotationFactory;
import org.pentaho.agilebi.modeler.nodes.annotations.IAnnotationFactory;
import org.pentaho.agilebi.modeler.nodes.annotations.IMemberAnnotation;
import org.pentaho.agilebi.modeler.nodes.annotations.MemberAnnotationFactory;
import org.pentaho.agilebi.modeler.strategy.MultiTableAutoModelStrategy;
import org.pentaho.agilebi.modeler.strategy.SimpleAutoModelStrategy;
import org.pentaho.agilebi.modeler.strategy.StarSchemaAutoModelStrategy;
import org.pentaho.metadata.model.*;
import org.pentaho.metadata.model.concept.types.AggregationType;
import org.pentaho.metadata.model.concept.types.LocalizedString;
import org.pentaho.metadata.model.olap.*;
import org.pentaho.ui.xul.XulEventSourceAdapter;
import org.pentaho.ui.xul.stereotype.Bindable;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;


/**
 * UI model behind the XUL-based interface. This class contains a reference from the context in
 * which the modeling was initiated through an IModelerSource which also provides model generation.
 *
 * @author nbaker
 */
@SuppressWarnings("unchecked")
public class ModelerWorkspace extends XulEventSourceAdapter implements Serializable{

  private static final long serialVersionUID = 2058731810283858276L;
  private AvailableItemCollection availableTables = new AvailableItemCollection();

  private MainModelNode model;
  private RelationalModelNode relationalModel;

  private String sourceName;

  private transient IModelerSource source;

  private String selectedServer;

  private String selectedVisualization;

  private String schemaName;

  private Domain domain;

  private boolean dirty = true;

  // full path to file
  private String fileName;

  private boolean modelIsChanging;

  private boolean isTemporary;

  private AbstractMetaDataModelNode selectedNode;
  private IAvailableItem selectedAvailableItem;
  private IModelerWorkspaceHelper workspaceHelper;
  private AbstractMetaDataModelNode selectedRelationalNode;

  private transient ModelerMode currentModellingMode = ModelerMode.ANALYSIS_AND_REPORTING;
  private transient ModelerPerspective currentModelerPerspective = ModelerPerspective.ANALYSIS;

  private transient SimpleAutoModelStrategy simpleAutoModelStrategy;
  private transient MultiTableAutoModelStrategy multiTableAutoModelStrategy;
  private transient StarSchemaAutoModelStrategy starSchemaAutoModelStrategy;

  private GeoContext geoContext;

  private transient ModelerTreeHelper currentModelerTreeHelper;

  public ModelerWorkspace(IModelerWorkspaceHelper helper) {
    this(helper, null);
  }
  public ModelerWorkspace(IModelerWorkspaceHelper helper, GeoContext geoContext) {

    this.isTemporary = true;
    this.workspaceHelper = helper;

    setModel(new MainModelNode(this));
    setRelationalModel(new RelationalModelNode(this));

    this.geoContext = geoContext;
    simpleAutoModelStrategy = new SimpleAutoModelStrategy(workspaceHelper.getLocale(), geoContext);
    multiTableAutoModelStrategy = new MultiTableAutoModelStrategy(workspaceHelper.getLocale());
    starSchemaAutoModelStrategy = new StarSchemaAutoModelStrategy(workspaceHelper.getLocale(), geoContext);
  }

  public GeoContext getGeoContext() {
    return geoContext;
  }

  @Bindable
  public MainModelNode getModel() {
    return model;
  }

  @Bindable
  public void setModel( MainModelNode model ) {
    this.model = model;
    model.addPropertyChangeListener("children", new PropertyChangeListener() { //$NON-NLS-1$

      public void propertyChange( PropertyChangeEvent arg0 ) {
        if (!modelIsChanging) {
          fireModelChanged();
        }
      }
    });
    model.addPropertyChangeListener("valid", new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        isValid();
      }
    });
  }

  @Bindable
  public RelationalModelNode getRelationalModel() {
    return relationalModel;
  }

  @Bindable
  public void setRelationalModel( RelationalModelNode model ) {
    this.relationalModel = model;
    relationalModel.addPropertyChangeListener("children", new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        if (!modelIsChanging) {
          fireRelationalModelChanged();
        }
      }
    });
    relationalModel.addPropertyChangeListener("valid", new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        isValid();
      }
    });
  }


  @Bindable
  public void setFileName( String fileName ) {
    String prevVal = this.fileName;
    String prevFriendly = getShortFileName();

    this.fileName = fileName;
    firePropertyChange("fileName", prevVal, fileName); //$NON-NLS-1$
    firePropertyChange("shortFileName", prevFriendly, getShortFileName()); //$NON-NLS-1$
  }

  @Bindable
  public String getShortFileName() {

    if (fileName == null) {
      return null;
    }
    int extensionPos = fileName.lastIndexOf('.');
    if (extensionPos == -1) {
      extensionPos = fileName.length();
    }
    int sepPos = fileName.replace('\\', '/').lastIndexOf('/');
    if (sepPos == -1) {
      sepPos = 0;
    } else {
      sepPos++;
    }
    return fileName.substring(sepPos, extensionPos);
  }

  @Bindable
  public String getFileName() {
    return fileName;
  }

  //transMeta.getFilename()

  @Bindable
  public String getSourceName() {
    return sourceName;
  }

  @Bindable
  public void setSourceName( String sourceName ) {
    this.sourceName = sourceName;
    this.firePropertyChange("sourceName", null, sourceName); //$NON-NLS-1$
  }

  @Bindable
  public String getModelName() {
    return model.getName();
  }

  @Bindable
  public void setModelName( String modelName ) {
    String prevVal = model.getName();
    model.setName(modelName);
    setDirty(true);
    this.firePropertyChange("modelName", prevVal, modelName); //$NON-NLS-1$
  }

  @Bindable
  public String getRelationalModelName() {
    return relationalModel.getName();
  }
  @Bindable
  public void setRelationalModelName(String modelName) {
    String prevVal = model.getName();
    relationalModel.setName(modelName);
    setDirty(true);
    this.firePropertyChange("relationalModelName", prevVal, modelName); //$NON-NLS-1$
  }

  @Bindable
  public boolean isDirty() {
    return dirty;
  }

  @Bindable
  public boolean isValid() {
    boolean valid = false;
    switch (getModellingMode()) {
      case ANALYSIS_AND_REPORTING:
        valid = this.model.isValid() && relationalModel.isValid();
        break;
      case REPORTING_ONLY:
        valid = relationalModel.isValid();
    }
    firePropertyChange("valid", null, valid);
    return valid;
  }

  @Bindable
  public List<String> getValidationMessages() {
    Set<String> modelMsg = model.getValidationMessages();
    Set<String> relModelMsg = relationalModel.getValidationMessages();
    modelMsg.addAll(relModelMsg);
    return new ArrayList<String>(modelMsg);
  }

  @Bindable
  public void setDirty( boolean dirty ) {
    boolean prevVal = this.dirty;
    this.dirty = dirty;
    this.firePropertyChange("dirty", prevVal, this.dirty); //$NON-NLS-1$
  }

  @Bindable
  public AvailableItemCollection getAvailableTables() {
    return availableTables;
  }

  @Bindable
  public void setSelectedVisualization( String aVisualization ) {
    this.selectedVisualization = aVisualization;
  }

  @Bindable
  public String getSelectedVisualization() {
    return this.selectedVisualization;
  }

  public DimensionMetaData createDimensionFromNode( ColumnBackedNode obj ) {
    DimensionMetaData dimension = new DimensionMetaData(obj.getName());
    dimension.setExpanded(true);
    HierarchyMetaData hierarchy = createHierarchyForParentWithNode(dimension, obj);
    hierarchy.setParent(dimension);
    hierarchy.setExpanded(true);
    dimension.add(hierarchy);
    return dimension;
  }


  public DimensionMetaData createDimensionFromAvailableTable(AvailableTable tbl) {
    DimensionMetaData dimension = new DimensionMetaData(tbl.getName());
    dimension.setExpanded(true);
    HierarchyMetaData hierarchy = new HierarchyMetaData(tbl.getName());

    hierarchy.setExpanded(true);
    for(AvailableField field : tbl.getChildren()){
      ColumnBackedNode node = this.createColumnBackedNode(field, ModelerPerspective.ANALYSIS);
      LevelMetaData level = createLevelForParentWithNode(hierarchy, node);
      hierarchy.add(level);
    }
    
    hierarchy.setParent(dimension);
    hierarchy.setExpanded(true);
    dimension.add(hierarchy);
    return dimension;
  }

  public DimensionMetaData createDimensionWithName( String dimName ) {
    DimensionMetaData dimension = new DimensionMetaData(dimName);
    dimension.setExpanded(true);
    HierarchyMetaData hierarchy = createHierarchyForParentWithNode(dimension, null);
    hierarchy.setParent(dimension);
    hierarchy.setExpanded(true);
    dimension.add(hierarchy);
    return dimension;
  }


  public void addDimensionFromNode( ColumnBackedNode obj ) {
    addDimension(createDimensionFromNode(obj));
  }

  public void addDimension( DimensionMetaData dim ) {
    boolean prevChangeState = this.modelIsChanging;
    this.setModelIsChanging(true);
    this.model.getDimensions().add(dim);
    this.setModelIsChanging(prevChangeState);
  }

  public void addCategory( CategoryMetaData cat ) {
    boolean prevChangeState = this.modelIsChanging;
    this.setRelationalModelIsChanging(true);
    this.relationalModel.getCategories().add(cat);
    this.setRelationalModelIsChanging(prevChangeState);
  }


  public LevelMetaData createLevelForParentWithNode( HierarchyMetaData parent, ColumnBackedNode obj ) {
    LevelMetaData level = new LevelMetaData(parent, obj.getName());
    level.setParent(parent);
    level.setLogicalColumn(obj.getLogicalColumn());
    return level;
  }

  public LevelMetaData createLevelForParentWithNode( HierarchyMetaData parent, String name ) {
    LevelMetaData level = new LevelMetaData(parent, name);
    level.setParent(parent);
    level.setLogicalColumn(findLogicalColumn(name));
    return level;
  }

  public MemberPropertyMetaData createMemberPropertyForParentWithNode( LevelMetaData parent, ColumnBackedNode obj ) {
    MemberPropertyMetaData memberProp = new MemberPropertyMetaData(parent, obj.getName());
    memberProp.setParent(parent);
    memberProp.setLogicalColumn(obj.getLogicalColumn());
    return memberProp;
  }

  public MemberPropertyMetaData createMemberPropertyForParentWithNode( LevelMetaData parent, String name ) {
    MemberPropertyMetaData memberProp = new MemberPropertyMetaData(parent, name);
    memberProp.setParent(parent);
    memberProp.setLogicalColumn(findLogicalColumn(name));
    return memberProp;
  }

  public FieldMetaData createFieldForParentWithNode( CategoryMetaData parent, AvailableField selectedField ) {
    FieldMetaData field = new FieldMetaData(parent, selectedField.getName(), "",
        selectedField.getDisplayName(), workspaceHelper.getLocale()); //$NON-NLS-1$
    ColumnBackedNode node = createColumnBackedNode(selectedField, ModelerPerspective.REPORTING);
    field.setLogicalColumn(node.getLogicalColumn());
    field.setFieldTypeDesc(node.getLogicalColumn().getDataType().getName());
    return field;
  }

  public HierarchyMetaData createHierarchyForParentWithNode( DimensionMetaData parent, ColumnBackedNode obj ) {
    HierarchyMetaData hier = new HierarchyMetaData(obj.getName());
    hier.setParent(parent);
    hier.setExpanded(true);
    if (obj != null) {
      LevelMetaData level = createLevelForParentWithNode(hier, obj);
      hier.add(level);
    }
    return hier;
  }

  private void fireTablesChanged() {
    // set the automodel strategy based on the number of available tables
    if (availableTables.size() > 1) {
      if (availableTables.findFactTable() != null) {
        workspaceHelper.setAutoModelStrategy(starSchemaAutoModelStrategy);
      } else {
        workspaceHelper.setAutoModelStrategy(multiTableAutoModelStrategy);
      }
    } else {
      workspaceHelper.setAutoModelStrategy(simpleAutoModelStrategy);
    }
    firePropertyChange("availableTables", null, this.availableTables); //$NON-NLS-1$
  }

  private void fireModelChanged() {
    firePropertyChange("model", null, model); //$NON-NLS-1$
    setDirty(true);
  }

  private void fireRelationalModelChanged() {
    firePropertyChange("relationalModel", null, relationalModel); //$NON-NLS-1$
    setDirty(true);
  }

  public MeasureMetaData createMeasureForNode( AvailableField selectedField ) {

    MeasureMetaData meta = new MeasureMetaData(selectedField.getName(), "",
        selectedField.getDisplayName(), workspaceHelper.getLocale()); //$NON-NLS-1$
    ColumnBackedNode node = createColumnBackedNode(selectedField, ModelerPerspective.ANALYSIS);
    meta.setLogicalColumn(node.getLogicalColumn());
    return meta;
  }

  public void addMeasure( MeasureMetaData measure) {

    boolean prevChangeState = isModelChanging();
    this.setModelIsChanging(true);
    this.model.getMeasures().add(measure);
    this.setModelIsChanging(prevChangeState);
  }

  public LogicalColumn findLogicalColumn( String id ) {
    LogicalColumn col = null;
    for (LogicalColumn c : getLogicalModel(currentModelerPerspective).getLogicalTables().get(0).getLogicalColumns()) {
      if (c.getName(workspaceHelper.getLocale()).equals(id)) {
        col = c;
        break;
      }
    }
    return col;
  }

  public LogicalTable findLogicalTable(IPhysicalTable table) {
    return findLogicalTable(table, currentModelerPerspective);
  }
  public LogicalTable findLogicalTable(IPhysicalTable table, ModelerPerspective perspective) {
    LogicalModel logicalModel = this.getLogicalModel(perspective);

    for (LogicalTable logicalTable : logicalModel.getLogicalTables()) {
      if (logicalTable.getPhysicalTable().equals(table)
          || logicalTable.getPhysicalTable().getId().equals(table.getId())
          || logicalTable.getId().equals(table.getId())) {

        return logicalTable;
//        boolean isOlapTable = logicalTable.getId().endsWith(BaseModelerWorkspaceHelper.OLAP_SUFFIX);
//        if (perspective == ModelerPerspective.ANALYSIS && isOlapTable) {
//          return logicalTable;
//        } else if (perspective == ModelerPerspective.REPORTING && !isOlapTable) {
//          return logicalTable;
//        }
      }
    }
    return null;
  }


  public void setModelSource( IModelerSource source ) {
    this.source = source;
  }

  public IModelerSource getModelSource() {
    return source;
  }

  public void setFields( List<MeasureMetaData> fields ) {
    this.model.getMeasures().clear();
    this.model.getMeasures().addAll(fields);
  }

  public void refresh(ModelerMode mode) throws ModelerException {
    if (source == null) {
      return;
    }

    Domain newDomain = source.generateDomain(mode == ModelerMode.ANALYSIS_AND_REPORTING);
    refresh(newDomain);
  }

  public boolean supportsOlap(Domain d){
    if(d.getLogicalModels().size() == 0){
      return false;
    }
    LogicalModel lModel = this.getLogicalModel(ModelerPerspective.ANALYSIS);
    return "true".equals(lModel.getProperty("DUAL_MODELING_SCHEMA")) || lModel.getProperty("MondrianCatalogRef") != null;
  }

  public void refresh(Domain newDomain) throws ModelerException {


    List<IAvailableItem> items = new ArrayList<IAvailableItem>();
    for (IPhysicalTable table : newDomain.getPhysicalModels().get(0).getPhysicalTables()) {<commit_msg>BISERVER-7036 - The Waiting box go on forever when updating Database Table Data Source from "Reporting and Analysis" to "Reporting only".<commit_after>/*
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * 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 Lesser General Public License for more details.
 *
 * Copyright (c) 2009 Pentaho Corporation..  All rights reserved.
 */
package org.pentaho.agilebi.modeler;

import org.pentaho.agilebi.modeler.geo.GeoContext;
import org.pentaho.agilebi.modeler.nodes.*;
import org.pentaho.agilebi.modeler.nodes.annotations.GeoAnnotationFactory;
import org.pentaho.agilebi.modeler.nodes.annotations.IAnnotationFactory;
import org.pentaho.agilebi.modeler.nodes.annotations.IMemberAnnotation;
import org.pentaho.agilebi.modeler.nodes.annotations.MemberAnnotationFactory;
import org.pentaho.agilebi.modeler.strategy.MultiTableAutoModelStrategy;
import org.pentaho.agilebi.modeler.strategy.SimpleAutoModelStrategy;
import org.pentaho.agilebi.modeler.strategy.StarSchemaAutoModelStrategy;
import org.pentaho.metadata.model.*;
import org.pentaho.metadata.model.concept.types.AggregationType;
import org.pentaho.metadata.model.concept.types.LocalizedString;
import org.pentaho.metadata.model.olap.*;
import org.pentaho.ui.xul.XulEventSourceAdapter;
import org.pentaho.ui.xul.stereotype.Bindable;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;


/**
 * UI model behind the XUL-based interface. This class contains a reference from the context in
 * which the modeling was initiated through an IModelerSource which also provides model generation.
 *
 * @author nbaker
 */
@SuppressWarnings("unchecked")
public class ModelerWorkspace extends XulEventSourceAdapter implements Serializable{

  private static final long serialVersionUID = 2058731810283858276L;
  private AvailableItemCollection availableTables = new AvailableItemCollection();

  private MainModelNode model;
  private RelationalModelNode relationalModel;

  private String sourceName;

  private transient IModelerSource source;

  private String selectedServer;

  private String selectedVisualization;

  private String schemaName;

  private Domain domain;

  private boolean dirty = true;

  // full path to file
  private String fileName;

  private boolean modelIsChanging;

  private boolean isTemporary;

  private AbstractMetaDataModelNode selectedNode;
  private IAvailableItem selectedAvailableItem;
  private IModelerWorkspaceHelper workspaceHelper;
  private AbstractMetaDataModelNode selectedRelationalNode;

  private transient ModelerMode currentModellingMode = ModelerMode.ANALYSIS_AND_REPORTING;
  private transient ModelerPerspective currentModelerPerspective = ModelerPerspective.ANALYSIS;

  private transient SimpleAutoModelStrategy simpleAutoModelStrategy;
  private transient MultiTableAutoModelStrategy multiTableAutoModelStrategy;
  private transient StarSchemaAutoModelStrategy starSchemaAutoModelStrategy;

  private GeoContext geoContext;

  private transient ModelerTreeHelper currentModelerTreeHelper;

  public ModelerWorkspace(IModelerWorkspaceHelper helper) {
    this(helper, null);
  }
  public ModelerWorkspace(IModelerWorkspaceHelper helper, GeoContext geoContext) {

    this.isTemporary = true;
    this.workspaceHelper = helper;

    setModel(new MainModelNode(this));
    setRelationalModel(new RelationalModelNode(this));

    this.geoContext = geoContext;
    simpleAutoModelStrategy = new SimpleAutoModelStrategy(workspaceHelper.getLocale(), geoContext);
    multiTableAutoModelStrategy = new MultiTableAutoModelStrategy(workspaceHelper.getLocale());
    starSchemaAutoModelStrategy = new StarSchemaAutoModelStrategy(workspaceHelper.getLocale(), geoContext);
  }

  public GeoContext getGeoContext() {
    return geoContext;
  }

  @Bindable
  public MainModelNode getModel() {
    return model;
  }

  @Bindable
  public void setModel( MainModelNode model ) {
    this.model = model;
    model.addPropertyChangeListener("children", new PropertyChangeListener() { //$NON-NLS-1$

      public void propertyChange( PropertyChangeEvent arg0 ) {
        if (!modelIsChanging) {
          fireModelChanged();
        }
      }
    });
    model.addPropertyChangeListener("valid", new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        isValid();
      }
    });
  }

  @Bindable
  public RelationalModelNode getRelationalModel() {
    return relationalModel;
  }

  @Bindable
  public void setRelationalModel( RelationalModelNode model ) {
    this.relationalModel = model;
    relationalModel.addPropertyChangeListener("children", new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        if (!modelIsChanging) {
          fireRelationalModelChanged();
        }
      }
    });
    relationalModel.addPropertyChangeListener("valid", new PropertyChangeListener() {
      public void propertyChange(PropertyChangeEvent evt) {
        isValid();
      }
    });
  }


  @Bindable
  public void setFileName( String fileName ) {
    String prevVal = this.fileName;
    String prevFriendly = getShortFileName();

    this.fileName = fileName;
    firePropertyChange("fileName", prevVal, fileName); //$NON-NLS-1$
    firePropertyChange("shortFileName", prevFriendly, getShortFileName()); //$NON-NLS-1$
  }

  @Bindable
  public String getShortFileName() {

    if (fileName == null) {
      return null;
    }
    int extensionPos = fileName.lastIndexOf('.');
    if (extensionPos == -1) {
      extensionPos = fileName.length();
    }
    int sepPos = fileName.replace('\\', '/').lastIndexOf('/');
    if (sepPos == -1) {
      sepPos = 0;
    } else {
      sepPos++;
    }
    return fileName.substring(sepPos, extensionPos);
  }

  @Bindable
  public String getFileName() {
    return fileName;
  }

  //transMeta.getFilename()

  @Bindable
  public String getSourceName() {
    return sourceName;
  }

  @Bindable
  public void setSourceName( String sourceName ) {
    this.sourceName = sourceName;
    this.firePropertyChange("sourceName", null, sourceName); //$NON-NLS-1$
  }

  @Bindable
  public String getModelName() {
    return model.getName();
  }

  @Bindable
  public void setModelName( String modelName ) {
    String prevVal = model.getName();
    model.setName(modelName);
    setDirty(true);
    this.firePropertyChange("modelName", prevVal, modelName); //$NON-NLS-1$
  }

  @Bindable
  public String getRelationalModelName() {
    return relationalModel.getName();
  }
  @Bindable
  public void setRelationalModelName(String modelName) {
    String prevVal = model.getName();
    relationalModel.setName(modelName);
    setDirty(true);
    this.firePropertyChange("relationalModelName", prevVal, modelName); //$NON-NLS-1$
  }

  @Bindable
  public boolean isDirty() {
    return dirty;
  }

  @Bindable
  public boolean isValid() {
    boolean valid = false;
    switch (getModellingMode()) {
      case ANALYSIS_AND_REPORTING:
        valid = this.model.isValid() && relationalModel.isValid();
        break;
      case REPORTING_ONLY:
        valid = relationalModel.isValid();
    }
    firePropertyChange("valid", null, valid);
    return valid;
  }

  @Bindable
  public List<String> getValidationMessages() {
    Set<String> modelMsg = model.getValidationMessages();
    Set<String> relModelMsg = relationalModel.getValidationMessages();
    modelMsg.addAll(relModelMsg);
    return new ArrayList<String>(modelMsg);
  }

  @Bindable
  public void setDirty( boolean dirty ) {
    boolean prevVal = this.dirty;
    this.dirty = dirty;
    this.firePropertyChange("dirty", prevVal, this.dirty); //$NON-NLS-1$
  }

  @Bindable
  public AvailableItemCollection getAvailableTables() {
    return availableTables;
  }

  @Bindable
  public void setSelectedVisualization( String aVisualization ) {
    this.selectedVisualization = aVisualization;
  }

  @Bindable
  public String getSelectedVisualization() {
    return this.selectedVisualization;
  }

  public DimensionMetaData createDimensionFromNode( ColumnBackedNode obj ) {
    DimensionMetaData dimension = new DimensionMetaData(obj.getName());
    dimension.setExpanded(true);
    HierarchyMetaData hierarchy = createHierarchyForParentWithNode(dimension, obj);
    hierarchy.setParent(dimension);
    hierarchy.setExpanded(true);
    dimension.add(hierarchy);
    return dimension;
  }


  public DimensionMetaData createDimensionFromAvailableTable(AvailableTable tbl) {
    DimensionMetaData dimension = new DimensionMetaData(tbl.getName());
    dimension.setExpanded(true);
    HierarchyMetaData hierarchy = new HierarchyMetaData(tbl.getName());

    hierarchy.setExpanded(true);
    for(AvailableField field : tbl.getChildren()){
      ColumnBackedNode node = this.createColumnBackedNode(field, ModelerPerspective.ANALYSIS);
      LevelMetaData level = createLevelForParentWithNode(hierarchy, node);
      hierarchy.add(level);
    }
    
    hierarchy.setParent(dimension);
    hierarchy.setExpanded(true);
    dimension.add(hierarchy);
    return dimension;
  }

  public DimensionMetaData createDimensionWithName( String dimName ) {
    DimensionMetaData dimension = new DimensionMetaData(dimName);
    dimension.setExpanded(true);
    HierarchyMetaData hierarchy = createHierarchyForParentWithNode(dimension, null);
    hierarchy.setParent(dimension);
    hierarchy.setExpanded(true);
    dimension.add(hierarchy);
    return dimension;
  }


  public void addDimensionFromNode( ColumnBackedNode obj ) {
    addDimension(createDimensionFromNode(obj));
  }

  public void addDimension( DimensionMetaData dim ) {
    boolean prevChangeState = this.modelIsChanging;
    this.setModelIsChanging(true);
    this.model.getDimensions().add(dim);
    this.setModelIsChanging(prevChangeState);
  }

  public void addCategory( CategoryMetaData cat ) {
    boolean prevChangeState = this.modelIsChanging;
    this.setRelationalModelIsChanging(true);
    this.relationalModel.getCategories().add(cat);
    this.setRelationalModelIsChanging(prevChangeState);
  }


  public LevelMetaData createLevelForParentWithNode( HierarchyMetaData parent, ColumnBackedNode obj ) {
    LevelMetaData level = new LevelMetaData(parent, obj.getName());
    level.setParent(parent);
    level.setLogicalColumn(obj.getLogicalColumn());
    return level;
  }

  public LevelMetaData createLevelForParentWithNode( HierarchyMetaData parent, String name ) {
    LevelMetaData level = new LevelMetaData(parent, name);
    level.setParent(parent);
    level.setLogicalColumn(findLogicalColumn(name));
    return level;
  }

  public MemberPropertyMetaData createMemberPropertyForParentWithNode( LevelMetaData parent, ColumnBackedNode obj ) {
    MemberPropertyMetaData memberProp = new MemberPropertyMetaData(parent, obj.getName());
    memberProp.setParent(parent);
    memberProp.setLogicalColumn(obj.getLogicalColumn());
    return memberProp;
  }

  public MemberPropertyMetaData createMemberPropertyForParentWithNode( LevelMetaData parent, String name ) {
    MemberPropertyMetaData memberProp = new MemberPropertyMetaData(parent, name);
    memberProp.setParent(parent);
    memberProp.setLogicalColumn(findLogicalColumn(name));
    return memberProp;
  }

  public FieldMetaData createFieldForParentWithNode( CategoryMetaData parent, AvailableField selectedField ) {
    FieldMetaData field = new FieldMetaData(parent, selectedField.getName(), "",
        selectedField.getDisplayName(), workspaceHelper.getLocale()); //$NON-NLS-1$
    ColumnBackedNode node = createColumnBackedNode(selectedField, ModelerPerspective.REPORTING);
    field.setLogicalColumn(node.getLogicalColumn());
    field.setFieldTypeDesc(node.getLogicalColumn().getDataType().getName());
    return field;
  }

  public HierarchyMetaData createHierarchyForParentWithNode( DimensionMetaData parent, ColumnBackedNode obj ) {
    HierarchyMetaData hier = new HierarchyMetaData(obj.getName());
    hier.setParent(parent);
    hier.setExpanded(true);
    if (obj != null) {
      LevelMetaData level = createLevelForParentWithNode(hier, obj);
      hier.add(level);
    }
    return hier;
  }

  private void fireTablesChanged() {
    // set the automodel strategy based on the number of available tables
    if (availableTables.size() > 1) {
      if (availableTables.findFactTable() != null) {
        workspaceHelper.setAutoModelStrategy(starSchemaAutoModelStrategy);
      } else {
        workspaceHelper.setAutoModelStrategy(multiTableAutoModelStrategy);
      }
    } else {
      workspaceHelper.setAutoModelStrategy(simpleAutoModelStrategy);
    }
    firePropertyChange("availableTables", null, this.availableTables); //$NON-NLS-1$
  }

  private void fireModelChanged() {
    firePropertyChange("model", null, model); //$NON-NLS-1$
    setDirty(true);
  }

  private void fireRelationalModelChanged() {
    firePropertyChange("relationalModel", null, relationalModel); //$NON-NLS-1$
    setDirty(true);
  }

  public MeasureMetaData createMeasureForNode( AvailableField selectedField ) {

    MeasureMetaData meta = new MeasureMetaData(selectedField.getName(), "",
        selectedField.getDisplayName(), workspaceHelper.getLocale()); //$NON-NLS-1$
    ColumnBackedNode node = createColumnBackedNode(selectedField, ModelerPerspective.ANALYSIS);
    meta.setLogicalColumn(node.getLogicalColumn());
    return meta;
  }

  public void addMeasure( MeasureMetaData measure) {

    boolean prevChangeState = isModelChanging();
    this.setModelIsChanging(true);
    this.model.getMeasures().add(measure);
    this.setModelIsChanging(prevChangeState);
  }

  public LogicalColumn findLogicalColumn( String id ) {
    LogicalColumn col = null;
    for (LogicalColumn c : getLogicalModel(currentModelerPerspective).getLogicalTables().get(0).getLogicalColumns()) {
      if (c.getName(workspaceHelper.getLocale()).equals(id)) {
        col = c;
        break;
      }
    }
    return col;
  }

  public LogicalTable findLogicalTable(IPhysicalTable table) {
    return findLogicalTable(table, currentModelerPerspective);
  }
  public LogicalTable findLogicalTable(IPhysicalTable table, ModelerPerspective perspective) {
    LogicalModel logicalModel = this.getLogicalModel(perspective);

    for (LogicalTable logicalTable : logicalModel.getLogicalTables()) {
      if (logicalTable.getPhysicalTable().equals(table)
          || logicalTable.getPhysicalTable().getId().equals(table.getId())
          || logicalTable.getId().equals(table.getId())) {

        return logicalTable;
//        boolean isOlapTable = logicalTable.getId().endsWith(BaseModelerWorkspaceHelper.OLAP_SUFFIX);
//        if (perspective == ModelerPerspective.ANALYSIS && isOlapTable) {
//          return logicalTable;
//        } else if (perspective == ModelerPerspective.REPORTING && !isOlapTable) {
//          return logicalTable;
//        }
      }
    }
    return null;
  }


  public void setModelSource( IModelerSource source ) {
    this.source = source;
  }

  public IModelerSource getModelSource() {
    return source;
  }

  public void setFields( List<MeasureMetaData> fields ) {
    this.model.getMeasures().clear();
    this.model.getMeasures().addAll(fields);
  }

  public void refresh(ModelerMode mode) throws ModelerException {
    if (source == null) {
      return;
    }

    Domain newDomain = source.generateDomain(mode == ModelerMode.ANALYSIS_AND_REPORTING);
    refresh(newDomain);
  }

  public boolean supportsOlap(Domain d){
    if(d.getLogicalModels().size() < 2){
      return false;
    } else {
      LogicalModel lModel = d.getLogicalModels().get(1);
      return "true".equals(lModel.getProperty("DUAL_MODELING_SCHEMA")) || lModel.getProperty("MondrianCatalogRef") != null;
    }
  }

  public void refresh(Domain newDomain) throws ModelerException {


    List<IAvailableItem> items = new ArrayList<IAvailableItem>();
    for (IPhysicalTable table : newDomain.getPhysicalModels().get(0).getPhysicalTables()) {
{'fraction_non_alphanumeric': 0.093723748949958, 'fraction_numerical': 0.0036301452058082324, 'mean_word_length': 4.32731340898194, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4735761', 'n_tokens_mistral': 9474, 'n_tokens_neox': 9370, 'n_words': 2034}