<commit_before>/*
 * Copyright 2008-2012 the original author or authors.
 *
 * 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 org.broadleafcommerce.openadmin.client.view.dynamic.form;

import com.google.gwt.core.client.GWT;
import com.smartgwt.client.data.DataSource;
import com.smartgwt.client.data.DataSourceField;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.events.FetchDataEvent;
import com.smartgwt.client.widgets.events.FetchDataHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.FormItemValueFormatter;
import com.smartgwt.client.widgets.form.fields.BooleanItem;
import com.smartgwt.client.widgets.form.fields.ComboBoxItem;
import com.smartgwt.client.widgets.form.fields.DateTimeItem;
import com.smartgwt.client.widgets.form.fields.FloatItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.FormItemIcon;
import com.smartgwt.client.widgets.form.fields.HeaderItem;
import com.smartgwt.client.widgets.form.fields.HiddenItem;
import com.smartgwt.client.widgets.form.fields.IntegerItem;
import com.smartgwt.client.widgets.form.fields.PasswordItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.TextAreaItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.UploadItem;
import com.smartgwt.client.widgets.form.fields.events.IconClickEvent;
import com.smartgwt.client.widgets.form.fields.events.IconClickHandler;
import com.smartgwt.client.widgets.form.validator.Validator;
import com.smartgwt.client.widgets.layout.Layout;
import com.smartgwt.client.widgets.tab.Tab;
import com.smartgwt.client.widgets.tab.TabSet;
import org.broadleafcommerce.common.presentation.client.AddMethodType;
import org.broadleafcommerce.common.presentation.client.PersistencePerspectiveItemType;
import org.broadleafcommerce.common.presentation.client.SupportedFieldType;
import org.broadleafcommerce.openadmin.client.BLCMain;
import org.broadleafcommerce.openadmin.client.datasource.dynamic.DynamicEntityDataSource;
import org.broadleafcommerce.openadmin.client.datasource.dynamic.ListGridDataSource;
import org.broadleafcommerce.openadmin.client.dto.AdornedTargetCollectionMetadata;
import org.broadleafcommerce.openadmin.client.dto.AdornedTargetList;
import org.broadleafcommerce.openadmin.client.dto.BasicCollectionMetadata;
import org.broadleafcommerce.openadmin.client.dto.CollectionMetadata;
import org.broadleafcommerce.openadmin.client.dto.MapMetadata;
import org.broadleafcommerce.openadmin.client.dto.MapStructure;
import org.broadleafcommerce.openadmin.client.dto.visitor.MetadataVisitorAdapter;
import org.broadleafcommerce.openadmin.client.presenter.entity.DynamicEntityPresenter;
import org.broadleafcommerce.openadmin.client.presenter.entity.SubPresentable;
import org.broadleafcommerce.openadmin.client.presenter.structure.CreateBasedListStructurePresenter;
import org.broadleafcommerce.openadmin.client.presenter.structure.EditableAdornedTargetListPresenter;
import org.broadleafcommerce.openadmin.client.presenter.structure.MapStructurePresenter;
import org.broadleafcommerce.openadmin.client.presenter.structure.SimpleMapStructurePresenter;
import org.broadleafcommerce.openadmin.client.presenter.structure.SimpleSearchListPresenter;
import org.broadleafcommerce.openadmin.client.security.SecurityManager;
import org.broadleafcommerce.openadmin.client.view.dynamic.dialog.EntitySearchDialog;
import org.broadleafcommerce.openadmin.client.view.dynamic.dialog.MapStructureEntityEditDialog;
import org.broadleafcommerce.openadmin.client.view.dynamic.grid.GridStructureView;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;

/**
 * 
 * @author jfischer
 *
 */
public class FormBuilder {

    public static Layout findMemberById(Layout parent, String id) {
        Layout result = (Layout) parent.getMember(id);
        if (result == null) {
            check: {
                for (Canvas member : parent.getMembers()) {
                    if (member instanceof Layout) {
                        result = findMemberById((Layout) member, id);
                        if (result != null) {
                            break check;
                        }
                    }
                    if (member instanceof TabSet) {
                        for (Tab tab : ((TabSet) member).getTabs()) {
                            if (tab.getPane().getID().equals(id)) {
                                result = (Layout) tab.getPane();
                                break check;
                            }
                            result = findMemberById((Layout) tab.getPane(), id);
                            if (result != null) {
                                break check;
                            }
                        }
                    }
                }
            }
        }

        return result;
    }

    public static void buildAdvancedCollectionForm(final DataSource dataSource, final DataSource lookupDataSource, CollectionMetadata metadata, String propertyName, final DynamicEntityPresenter presenter) {
        final Layout destination;
        if (metadata.getTargetElementId() != null && metadata.getTargetElementId().length() > 0) {
            destination = findMemberById((Layout) presenter.getDisplay(), metadata.getTargetElementId());
        } else {
            destination = (Layout) presenter.getDisplay().getDynamicFormDisplay().getFormOnlyDisplay();
        }

        final String viewTitle;
        if (metadata.getFriendlyName() == null || metadata.getFriendlyName().length() == 0) {
            viewTitle = propertyName;
        } else {
            String temp;
            try {
                temp = BLCMain.getMessageManager().getString(metadata.getFriendlyName());
            } catch (MissingResourceException e) {
                temp = metadata.getFriendlyName();
            }
            viewTitle = temp;
        }

        //make the grid readonly if it fails a security check
        if (metadata.getSecurityLevel() != null && !"".equals(metadata.getSecurityLevel())){
            org.broadleafcommerce.openadmin.client.security.SecurityManager.getInstance().registerField(String.valueOf(metadata.hashCode()), metadata.getSecurityLevel());
            Boolean shouldLoad = org.broadleafcommerce.openadmin.client.security.SecurityManager.getInstance().isUserAuthorizedToEditField(String.valueOf(metadata.hashCode()));
            if (!shouldLoad) {
                metadata.setMutable(false);
            }
        }

        metadata.accept(new MetadataVisitorAdapter() {
            @Override
            public void visit(BasicCollectionMetadata metadata) {
                GridStructureView advancedCollectionView = new GridStructureView(viewTitle, false, true);
                destination.addMember(advancedCollectionView);
                SubPresentable subPresentable;
                if (metadata.getAddMethodType() == AddMethodType.PERSIST) {
                    subPresentable = new CreateBasedListStructurePresenter(advancedCollectionView, metadata.getAvailableToTypes(), viewTitle, new HashMap<String, Object>());
                } else {
                    subPresentable = new SimpleSearchListPresenter(advancedCollectionView, new EntitySearchDialog((ListGridDataSource)lookupDataSource, true), metadata.getAvailableToTypes(), viewTitle);
                }
                subPresentable.setDataSource((ListGridDataSource) dataSource, new String[]{}, new Boolean[]{});
                subPresentable.setReadOnly(!metadata.isMutable());
                ((GridStructureView) subPresentable.getDisplay()).getToolBar().disable();
                presenter.setSubPresentable(dataSource.getDataURL(), subPresentable);
            }

            @Override
            public void visit(AdornedTargetCollectionMetadata metadata) {
                String sortField = ((AdornedTargetList) ((DynamicEntityDataSource) dataSource).getPersistencePerspective().getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.ADORNEDTARGETLIST)).getSortField();
                GridStructureView advancedCollectionView = new GridStructureView(viewTitle, sortField!=null&sortField.length()>0, true);
                destination.addMember(advancedCollectionView);
                List<String> prominentNames = new ArrayList<String>();
                for (DataSourceField field : lookupDataSource.getFields()) {
                    if (field.getAttributeAsBoolean("prominent") && !field.getAttributeAsBoolean("permanentlyHidden")) {
                        prominentNames.add(field.getName());
                    }
                }
                ((ListGridDataSource) lookupDataSource).resetPermanentFieldVisibility(prominentNames.toArray(new String[prominentNames.size()]));
                EntitySearchDialog searchView = new EntitySearchDialog((ListGridDataSource) lookupDataSource, true);
                SubPresentable subPresentable;
                if (metadata.isIgnoreAdornedProperties() || metadata.getMaintainedAdornedTargetFields().length == 0) {
                    subPresentable = new SimpleSearchListPresenter(advancedCollectionView, searchView, metadata.getAvailableToTypes(), viewTitle);
                } else {
                    subPresentable = new EditableAdornedTargetListPresenter(advancedCollectionView, searchView, metadata.getAvailableToTypes(), viewTitle, viewTitle, metadata.getMaintainedAdornedTargetFields());
                }
                Boolean[] edits = new Boolean[metadata.getGridVisibleFields().length];
                for (int j=0;j<edits.length;j++) {
                    edits[j] = false;
                }
                subPresentable.setDataSource((ListGridDataSource) dataSource, metadata.getGridVisibleFields(), edits);
                subPresentable.setReadOnly(!metadata.isMutable());
                ((GridStructureView) subPresentable.getDisplay()).getToolBar().disable();
                presenter.setSubPresentable(dataSource.getDataURL(), subPresentable);
            }

            @Override
            public void visit(MapMetadata metadata) {
                GridStructureView advancedCollectionView = new GridStructureView(viewTitle, false, true);
                destination.addMember(advancedCollectionView);
                SubPresentable subPresentable;
                if (metadata.isSimpleValue()) {
                    subPresentable = new SimpleMapStructurePresenter(advancedCollectionView, metadata.getAvailableToTypes(), null);
                } else {
                    MapStructureEntityEditDialog mapEntityAdd;
                    if (lookupDataSource != null) {
                        mapEntityAdd = new MapStructureEntityEditDialog((MapStructure) metadata.getPersistencePerspective().getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.MAPSTRUCTURE), lookupDataSource, metadata.getMapKeyOptionEntityDisplayField(), metadata.getMapKeyOptionEntityValueField());
                    } else {
                        LinkedHashMap<String, String> keys = new LinkedHashMap<String, String>();
                        for (String[] key : metadata.getKeys()) {
                            String temp;
                            try {
                                temp = BLCMain.getMessageManager().getString(key[1]);
                            } catch (MissingResourceException e) {
                                temp = key[1];
                            }
                            keys.put(key[0], temp);
                        }
                        mapEntityAdd = new MapStructureEntityEditDialog((MapStructure) metadata.getPersistencePerspective().getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.MAPSTRUCTURE), keys);
                    }
                    if (metadata.getMediaField() != null && metadata.getMediaField().length() > 0) {
                        mapEntityAdd.setShowMedia(true);
                        mapEntityAdd.setMediaField(metadata.getMediaField());
                    } else {
                        mapEntityAdd.setShowMedia(false);
                    }
                    subPresentable = new MapStructurePresenter(advancedCollectionView, mapEntityAdd, viewTitle, null);
                }
                subPresentable.setDataSource((ListGridDataSource) dataSource, new String[]{}, new Boolean[]{});
                subPresentable.setReadOnly(!metadata.isMutable());
                ((GridStructureView) subPresentable.getDisplay()).getToolBar().disable();
                presenter.setSubPresentable(dataSource.getDataURL(), subPresentable);
            }
        });
    }

    public static void buildAdvancedCollectionForm(DataSource dataSource, CollectionMetadata metadata, String propertyName, DynamicEntityPresenter presenter) {
        buildAdvancedCollectionForm(dataSource, null, metadata, propertyName, presenter);
    }

	public static void buildForm(final DataSource dataSource, DynamicForm form, Boolean showId, Record currentRecord) {
		buildForm(dataSource, form, null, null, showId, currentRecord);
	}
	
	public static void buildForm(final DataSource dataSource, DynamicForm form, Boolean showDisabledState, Boolean canEdit, Boolean showId, Record currentRecord) {
        String[] recordAttributes = currentRecord == null?null:currentRecord.getAttributes();
        if (recordAttributes != null) {
            Arrays.sort(recordAttributes);
        }
		form.setDataSource(dataSource);
		Map<String, List<FormItem>> sections = new HashMap<String, List<FormItem>>();
        Map<String, Boolean> sectionCollapsed = new HashMap<String, Boolean>();
		Map<String, Integer> sectionNames = new HashMap<String, Integer>();
		DataSourceField[] fields = dataSource.getFields();
		Boolean originalEdit = canEdit;
        for (DataSourceField field : fields) {

        	if (field.getAttribute("securityLevel") != null && field.getAttribute("uniqueID") != null && !SecurityManager.getInstance().isUserAuthorizedToEditField(field.getAttribute("uniqueID"))){
        		canEdit = false;
        	}
        	String name = field.getName();
        	String fieldType = field.getAttribute("fieldType");
            FormHiddenEnum enumVal = (FormHiddenEnum) field.getAttributeAsObject("formHidden");
            Boolean tempFormHidden = field.getAttribute("tempFormHidden") != null && Boolean.parseBoolean(field.getAttribute("tempFormHidden"));
            /*
                Check to make sure this field exists for this record. This could be a polymorphic type
                for this record that does not have this field. This is normally taken care of during inspection
                for a datasource ceiling entity. However, occasion can arise where there is a ManyToOne
                relationship on an entity to another entity with a polymorphic type (e.g. an OrderItem
                with a relationship to polymorphic product). In this instance, fields exposed for this
                related entity should be hidden or shown appropriately in the form based on the the
                type of this related entity. This only comes into play when the populateToOne property of
                the @AdminPresentationClass annotation has been set to true.
             */
            boolean isFieldAvailableForRecord = false;
            if (currentRecord != null) {
                int pos = Arrays.binarySearch(recordAttributes, name);
                isFieldAvailableForRecord = pos >= 0;
            } else {
                isFieldAvailableForRecord = true;
            }
        	if (fieldType != null && (!field.getHidden() || enumVal == FormHiddenEnum.VISIBLE) && enumVal != FormHiddenEnum.HIDDEN && isFieldAvailableForRecord && !tempFormHidden) {
	    		String group = field.getAttribute("formGroup");
	    		String temp = field.getAttribute("formGroupOrder");
                if (field.getAttributeAsBoolean("formGroupCollapsed") != null) {
                    sectionCollapsed.put(group, field.getAttributeAsBoolean("formGroupCollapsed"));
                }
	    		Integer groupOrder = null;
	    		if (temp != null) {
	    			groupOrder = Integer.valueOf(temp);
	    		}
	        	if (group == null) {
	        		if (fieldType.equals(SupportedFieldType.ID.toString())) {
	        			group = "Primary Key";
	        		} else {
	        			group = "General";
	        		}
	        	}
	        	if (!fieldType.equals(SupportedFieldType.ID.toString()) || (fieldType.equals(SupportedFieldType.ID.toString()) && showId)) {
		        	Boolean largeEntry = field.getAttributeAsBoolean("largeEntry");
		        	if (largeEntry == null) {
		        		largeEntry = false;
		        	}
		        	final FormItem formItem = buildField(dataSource, field, fieldType, largeEntry, form);
		        	final FormItem displayFormItem = buildDisplayField(field, fieldType);
		        	if (fieldType.equals(SupportedFieldType.ID.toString())) {
		        		canEdit = false;
		        		showDisabledState = false;
		        	}
		        	setupField(showDisabledState, canEdit, sections, sectionNames, field, group, groupOrder, formItem, displayFormItem);
		        	checkForPasswordField(showDisabledState, canEdit, sections, sectionNames, field, group, groupOrder, formItem, displayFormItem, form);
	        	}
        	}
        	
        	canEdit = originalEdit;
        }
        
        groupFields(form, sections, sectionNames, sectionCollapsed);
	}

    public static void buildMapForm(DataSource dataSource, DynamicForm form, MapStructure mapStructure, DataSource optionDataSource, String displayField, String valueField, Boolean showId, Record currentRecord) {
        buildMapForm(dataSource, form, mapStructure, null, optionDataSource, displayField, valueField, showId, currentRecord);
    }

    public static void buildMapForm(DataSource dataSource, DynamicForm form, MapStructure mapStructure, LinkedHashMap<String, String> mapKeys, Boolean showId, Record currentRecord) {
        buildMapForm(dataSource, form, mapStructure, mapKeys, null, null, null, showId, currentRecord);
    }
	
	private static void buildMapForm(DataSource dataSource, DynamicForm form, MapStructure mapStructure, LinkedHashMap<String, String> mapKeys, DataSource optionDataSource, String displayField, String valueField, Boolean showId, Record currentRecord) {
		if (mapKeys == null && optionDataSource == null) {
            throw new RuntimeException("Must provide either map keys or and option datasource to control the values for the key field.");<commit_msg>BLC-673 - @AdminPresentationToOneLookup fields show up no matter what when populateToOneFields is set to true (cherry picked from commit 3cc355f)<commit_after>/*
 * Copyright 2008-2012 the original author or authors.
 *
 * 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 org.broadleafcommerce.openadmin.client.view.dynamic.form;

import com.google.gwt.core.client.GWT;
import com.smartgwt.client.data.DataSource;
import com.smartgwt.client.data.DataSourceField;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.events.FetchDataEvent;
import com.smartgwt.client.widgets.events.FetchDataHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.FormItemValueFormatter;
import com.smartgwt.client.widgets.form.fields.BooleanItem;
import com.smartgwt.client.widgets.form.fields.ComboBoxItem;
import com.smartgwt.client.widgets.form.fields.DateTimeItem;
import com.smartgwt.client.widgets.form.fields.FloatItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.FormItemIcon;
import com.smartgwt.client.widgets.form.fields.HeaderItem;
import com.smartgwt.client.widgets.form.fields.HiddenItem;
import com.smartgwt.client.widgets.form.fields.IntegerItem;
import com.smartgwt.client.widgets.form.fields.PasswordItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.TextAreaItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.UploadItem;
import com.smartgwt.client.widgets.form.fields.events.IconClickEvent;
import com.smartgwt.client.widgets.form.fields.events.IconClickHandler;
import com.smartgwt.client.widgets.form.validator.Validator;
import com.smartgwt.client.widgets.layout.Layout;
import com.smartgwt.client.widgets.tab.Tab;
import com.smartgwt.client.widgets.tab.TabSet;
import org.broadleafcommerce.common.presentation.client.AddMethodType;
import org.broadleafcommerce.common.presentation.client.PersistencePerspectiveItemType;
import org.broadleafcommerce.common.presentation.client.SupportedFieldType;
import org.broadleafcommerce.openadmin.client.BLCMain;
import org.broadleafcommerce.openadmin.client.datasource.dynamic.DynamicEntityDataSource;
import org.broadleafcommerce.openadmin.client.datasource.dynamic.ListGridDataSource;
import org.broadleafcommerce.openadmin.client.dto.AdornedTargetCollectionMetadata;
import org.broadleafcommerce.openadmin.client.dto.AdornedTargetList;
import org.broadleafcommerce.openadmin.client.dto.BasicCollectionMetadata;
import org.broadleafcommerce.openadmin.client.dto.CollectionMetadata;
import org.broadleafcommerce.openadmin.client.dto.MapMetadata;
import org.broadleafcommerce.openadmin.client.dto.MapStructure;
import org.broadleafcommerce.openadmin.client.dto.visitor.MetadataVisitorAdapter;
import org.broadleafcommerce.openadmin.client.presenter.entity.DynamicEntityPresenter;
import org.broadleafcommerce.openadmin.client.presenter.entity.SubPresentable;
import org.broadleafcommerce.openadmin.client.presenter.structure.CreateBasedListStructurePresenter;
import org.broadleafcommerce.openadmin.client.presenter.structure.EditableAdornedTargetListPresenter;
import org.broadleafcommerce.openadmin.client.presenter.structure.MapStructurePresenter;
import org.broadleafcommerce.openadmin.client.presenter.structure.SimpleMapStructurePresenter;
import org.broadleafcommerce.openadmin.client.presenter.structure.SimpleSearchListPresenter;
import org.broadleafcommerce.openadmin.client.security.SecurityManager;
import org.broadleafcommerce.openadmin.client.view.dynamic.dialog.EntitySearchDialog;
import org.broadleafcommerce.openadmin.client.view.dynamic.dialog.MapStructureEntityEditDialog;
import org.broadleafcommerce.openadmin.client.view.dynamic.grid.GridStructureView;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;

/**
 * 
 * @author jfischer
 *
 */
public class FormBuilder {

    public static Layout findMemberById(Layout parent, String id) {
        Layout result = (Layout) parent.getMember(id);
        if (result == null) {
            check: {
                for (Canvas member : parent.getMembers()) {
                    if (member instanceof Layout) {
                        result = findMemberById((Layout) member, id);
                        if (result != null) {
                            break check;
                        }
                    }
                    if (member instanceof TabSet) {
                        for (Tab tab : ((TabSet) member).getTabs()) {
                            if (tab.getPane().getID().equals(id)) {
                                result = (Layout) tab.getPane();
                                break check;
                            }
                            result = findMemberById((Layout) tab.getPane(), id);
                            if (result != null) {
                                break check;
                            }
                        }
                    }
                }
            }
        }

        return result;
    }

    public static void buildAdvancedCollectionForm(final DataSource dataSource, final DataSource lookupDataSource, CollectionMetadata metadata, String propertyName, final DynamicEntityPresenter presenter) {
        final Layout destination;
        if (metadata.getTargetElementId() != null && metadata.getTargetElementId().length() > 0) {
            destination = findMemberById((Layout) presenter.getDisplay(), metadata.getTargetElementId());
        } else {
            destination = (Layout) presenter.getDisplay().getDynamicFormDisplay().getFormOnlyDisplay();
        }

        final String viewTitle;
        if (metadata.getFriendlyName() == null || metadata.getFriendlyName().length() == 0) {
            viewTitle = propertyName;
        } else {
            String temp;
            try {
                temp = BLCMain.getMessageManager().getString(metadata.getFriendlyName());
            } catch (MissingResourceException e) {
                temp = metadata.getFriendlyName();
            }
            viewTitle = temp;
        }

        //make the grid readonly if it fails a security check
        if (metadata.getSecurityLevel() != null && !"".equals(metadata.getSecurityLevel())){
            org.broadleafcommerce.openadmin.client.security.SecurityManager.getInstance().registerField(String.valueOf(metadata.hashCode()), metadata.getSecurityLevel());
            Boolean shouldLoad = org.broadleafcommerce.openadmin.client.security.SecurityManager.getInstance().isUserAuthorizedToEditField(String.valueOf(metadata.hashCode()));
            if (!shouldLoad) {
                metadata.setMutable(false);
            }
        }

        metadata.accept(new MetadataVisitorAdapter() {
            @Override
            public void visit(BasicCollectionMetadata metadata) {
                GridStructureView advancedCollectionView = new GridStructureView(viewTitle, false, true);
                destination.addMember(advancedCollectionView);
                SubPresentable subPresentable;
                if (metadata.getAddMethodType() == AddMethodType.PERSIST) {
                    subPresentable = new CreateBasedListStructurePresenter(advancedCollectionView, metadata.getAvailableToTypes(), viewTitle, new HashMap<String, Object>());
                } else {
                    subPresentable = new SimpleSearchListPresenter(advancedCollectionView, new EntitySearchDialog((ListGridDataSource)lookupDataSource, true), metadata.getAvailableToTypes(), viewTitle);
                }
                subPresentable.setDataSource((ListGridDataSource) dataSource, new String[]{}, new Boolean[]{});
                subPresentable.setReadOnly(!metadata.isMutable());
                ((GridStructureView) subPresentable.getDisplay()).getToolBar().disable();
                presenter.setSubPresentable(dataSource.getDataURL(), subPresentable);
            }

            @Override
            public void visit(AdornedTargetCollectionMetadata metadata) {
                String sortField = ((AdornedTargetList) ((DynamicEntityDataSource) dataSource).getPersistencePerspective().getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.ADORNEDTARGETLIST)).getSortField();
                GridStructureView advancedCollectionView = new GridStructureView(viewTitle, sortField!=null&sortField.length()>0, true);
                destination.addMember(advancedCollectionView);
                List<String> prominentNames = new ArrayList<String>();
                for (DataSourceField field : lookupDataSource.getFields()) {
                    if (field.getAttributeAsBoolean("prominent") && !field.getAttributeAsBoolean("permanentlyHidden")) {
                        prominentNames.add(field.getName());
                    }
                }
                ((ListGridDataSource) lookupDataSource).resetPermanentFieldVisibility(prominentNames.toArray(new String[prominentNames.size()]));
                EntitySearchDialog searchView = new EntitySearchDialog((ListGridDataSource) lookupDataSource, true);
                SubPresentable subPresentable;
                if (metadata.isIgnoreAdornedProperties() || metadata.getMaintainedAdornedTargetFields().length == 0) {
                    subPresentable = new SimpleSearchListPresenter(advancedCollectionView, searchView, metadata.getAvailableToTypes(), viewTitle);
                } else {
                    subPresentable = new EditableAdornedTargetListPresenter(advancedCollectionView, searchView, metadata.getAvailableToTypes(), viewTitle, viewTitle, metadata.getMaintainedAdornedTargetFields());
                }
                Boolean[] edits = new Boolean[metadata.getGridVisibleFields().length];
                for (int j=0;j<edits.length;j++) {
                    edits[j] = false;
                }
                subPresentable.setDataSource((ListGridDataSource) dataSource, metadata.getGridVisibleFields(), edits);
                subPresentable.setReadOnly(!metadata.isMutable());
                ((GridStructureView) subPresentable.getDisplay()).getToolBar().disable();
                presenter.setSubPresentable(dataSource.getDataURL(), subPresentable);
            }

            @Override
            public void visit(MapMetadata metadata) {
                GridStructureView advancedCollectionView = new GridStructureView(viewTitle, false, true);
                destination.addMember(advancedCollectionView);
                SubPresentable subPresentable;
                if (metadata.isSimpleValue()) {
                    subPresentable = new SimpleMapStructurePresenter(advancedCollectionView, metadata.getAvailableToTypes(), null);
                } else {
                    MapStructureEntityEditDialog mapEntityAdd;
                    if (lookupDataSource != null) {
                        mapEntityAdd = new MapStructureEntityEditDialog((MapStructure) metadata.getPersistencePerspective().getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.MAPSTRUCTURE), lookupDataSource, metadata.getMapKeyOptionEntityDisplayField(), metadata.getMapKeyOptionEntityValueField());
                    } else {
                        LinkedHashMap<String, String> keys = new LinkedHashMap<String, String>();
                        for (String[] key : metadata.getKeys()) {
                            String temp;
                            try {
                                temp = BLCMain.getMessageManager().getString(key[1]);
                            } catch (MissingResourceException e) {
                                temp = key[1];
                            }
                            keys.put(key[0], temp);
                        }
                        mapEntityAdd = new MapStructureEntityEditDialog((MapStructure) metadata.getPersistencePerspective().getPersistencePerspectiveItems().get(PersistencePerspectiveItemType.MAPSTRUCTURE), keys);
                    }
                    if (metadata.getMediaField() != null && metadata.getMediaField().length() > 0) {
                        mapEntityAdd.setShowMedia(true);
                        mapEntityAdd.setMediaField(metadata.getMediaField());
                    } else {
                        mapEntityAdd.setShowMedia(false);
                    }
                    subPresentable = new MapStructurePresenter(advancedCollectionView, mapEntityAdd, viewTitle, null);
                }
                subPresentable.setDataSource((ListGridDataSource) dataSource, new String[]{}, new Boolean[]{});
                subPresentable.setReadOnly(!metadata.isMutable());
                ((GridStructureView) subPresentable.getDisplay()).getToolBar().disable();
                presenter.setSubPresentable(dataSource.getDataURL(), subPresentable);
            }
        });
    }

    public static void buildAdvancedCollectionForm(DataSource dataSource, CollectionMetadata metadata, String propertyName, DynamicEntityPresenter presenter) {
        buildAdvancedCollectionForm(dataSource, null, metadata, propertyName, presenter);
    }

	public static void buildForm(final DataSource dataSource, DynamicForm form, Boolean showId, Record currentRecord) {
		buildForm(dataSource, form, null, null, showId, currentRecord);
	}
	
	public static void buildForm(final DataSource dataSource, DynamicForm form, Boolean showDisabledState, Boolean canEdit, Boolean showId, Record currentRecord) {
        String[] recordAttributes = currentRecord == null?null:currentRecord.getAttributes();
        if (recordAttributes != null) {
            Arrays.sort(recordAttributes);
        }
		form.setDataSource(dataSource);
		Map<String, List<FormItem>> sections = new HashMap<String, List<FormItem>>();
        Map<String, Boolean> sectionCollapsed = new HashMap<String, Boolean>();
		Map<String, Integer> sectionNames = new HashMap<String, Integer>();
		DataSourceField[] fields = dataSource.getFields();
		Boolean originalEdit = canEdit;
        for (DataSourceField field : fields) {

        	if (field.getAttribute("securityLevel") != null && field.getAttribute("uniqueID") != null && !SecurityManager.getInstance().isUserAuthorizedToEditField(field.getAttribute("uniqueID"))){
        		canEdit = false;
        	}
        	String name = field.getName();
        	String fieldType = field.getAttribute("fieldType");
            FormHiddenEnum enumVal = (FormHiddenEnum) field.getAttributeAsObject("formHidden");
            Boolean tempFormHidden = field.getAttribute("tempFormHidden") != null && Boolean.parseBoolean(field.getAttribute("tempFormHidden"));
            /*
                Check to make sure this field exists for this record. This could be a polymorphic type
                for this record that does not have this field. This is normally taken care of during inspection
                for a datasource ceiling entity. However, occasion can arise where there is a ManyToOne
                relationship on an entity to another entity with a polymorphic type (e.g. an OrderItem
                with a relationship to polymorphic product). In this instance, fields exposed for this
                related entity should be hidden or shown appropriately in the form based on the the
                type of this related entity. This only comes into play when the populateToOne property of
                the @AdminPresentationClass annotation has been set to true.
             */
            boolean isFieldAvailableForRecord = false;
            if (currentRecord != null) {
                int pos = Arrays.binarySearch(recordAttributes, name);
                isFieldAvailableForRecord = pos >= 0;
            } else {
                isFieldAvailableForRecord = true;
            }
        	if (fieldType != null && (!field.getHidden() || enumVal == FormHiddenEnum.VISIBLE) && enumVal != FormHiddenEnum.HIDDEN && isFieldAvailableForRecord && !tempFormHidden) {
	    		String group = field.getAttribute("formGroup");
	    		String temp = field.getAttribute("formGroupOrder");
                if (field.getAttributeAsBoolean("formGroupCollapsed") != null) {
                    sectionCollapsed.put(group, field.getAttributeAsBoolean("formGroupCollapsed"));
                }
	    		Integer groupOrder = null;
	    		if (temp != null) {
	    			groupOrder = Integer.valueOf(temp);
	    		}
	        	if (group == null) {
	        		if (fieldType.equals(SupportedFieldType.ID.toString())) {
	        			group = "Primary Key";
	        		} else {
	        			group = "General";
	        		}
	        	}
	        	if (!fieldType.equals(SupportedFieldType.ID.toString()) || (fieldType.equals(SupportedFieldType.ID.toString()) && showId)) {
		        	Boolean largeEntry = field.getAttributeAsBoolean("largeEntry");
		        	if (largeEntry == null) {
		        		largeEntry = false;
		        	}
		        	final FormItem formItem = buildField(dataSource, field, fieldType, largeEntry, form);
		        	final FormItem displayFormItem = buildDisplayField(field, fieldType);
		        	if (fieldType.equals(SupportedFieldType.ID.toString())) {
		        		canEdit = false;
		        		showDisabledState = false;
		        	}
		        	setupField(showDisabledState, canEdit, sections, sectionNames, field, group, groupOrder, formItem, displayFormItem);
		        	checkForPasswordField(showDisabledState, canEdit, sections, sectionNames, field, group, groupOrder, formItem, displayFormItem, form);
	        	}
        	}
            field.setAttribute("tempFormHidden", false);
        	
        	canEdit = originalEdit;
        }
        
        groupFields(form, sections, sectionNames, sectionCollapsed);
	}

    public static void buildMapForm(DataSource dataSource, DynamicForm form, MapStructure mapStructure, DataSource optionDataSource, String displayField, String valueField, Boolean showId, Record currentRecord) {
        buildMapForm(dataSource, form, mapStructure, null, optionDataSource, displayField, valueField, showId, currentRecord);
    }

    public static void buildMapForm(DataSource dataSource, DynamicForm form, MapStructure mapStructure, LinkedHashMap<String, String> mapKeys, Boolean showId, Record currentRecord) {
        buildMapForm(dataSource, form, mapStructure, mapKeys, null, null, null, showId, currentRecord);
    }
	
	private static void buildMapForm(DataSource dataSource, DynamicForm form, MapStructure mapStructure, LinkedHashMap<String, String> mapKeys, DataSource optionDataSource, String displayField, String valueField, Boolean showId, Record currentRecord) {
		if (mapKeys == null && optionDataSource == null) {
            throw new RuntimeException("Must provide either map keys or and option datasource to control the values for the key field.");
{'fraction_non_alphanumeric': 0.09106516001742383, 'fraction_numerical': 0.0013067876085786764, 'mean_word_length': 2.903971191357407, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 41, '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': '5942097', 'n_tokens_mistral': 9794, 'n_tokens_neox': 9343, 'n_words': 2015}