package ro.nextreports.server.web.analysis.feature.create;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.model.StringResourceModel;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.image.ContextImage;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.spring.injection.annot.SpringBean;

import ro.nextreports.server.domain.Analysis;
import ro.nextreports.server.domain.AnalysisDeclaredColumn;
import ro.nextreports.server.service.StorageService;
import ro.nextreports.server.util.AnalysisUtil;
import ro.nextreports.server.web.analysis.util.DatabaseUtil;
import ro.nextreports.server.web.common.behavior.SimpleTooltipBehavior;
import ro.nextreports.server.web.common.form.FormContentPanel;
import ro.nextreports.server.web.common.form.FormPanel;
import ro.nextreports.server.web.common.table.BaseTable;
import ro.nextreports.server.web.common.table.LinkPropertyColumn;
import ro.nextreports.server.web.core.validation.AnalysisNameValidator;

public class CreatePanel extends FormContentPanel<Analysis> {

	private AnalysisDeclaredColumn declaredColumnObject;
	private IModel<Analysis> model;
	private Label label;
	private DataTable<AnalysisDeclaredColumn, String> table;
	private DeclaredColumnObjectDataProvider provider;
	private TextField<String> nameText;		
	private TextArea<String> expressionText;
	private DropDownChoice<String> typeChoice;	
	private String selectedColumn;
	private String selectedAgg;
	
	private int editIndex = -1;
	private int oldColumnIndex = -1;
	private int oldFilterIndex = -1;
	private int oldSortIndex = -1;
	private int oldGroupIndex = -1;
	private IModel<String> addTextModel;
	
	@SpringBean
    private StorageService storageService;   
		
	public CreatePanel(IModel<Analysis> model) {		
		super(FormPanel.CONTENT_ID);	
		this.model = model;		
				
		ContextImage urlImage = new ContextImage("infoImage","images/information.png");        
        urlImage.add(new SimpleTooltipBehavior(AnalysisUtil.getAnalysisInfo(model.getObject(), 5, storageService.getSettings())));
        add(urlImage);
		
		declaredColumnObject = new AnalysisDeclaredColumn();
		declaredColumnObject.setType("java.lang.String");	
		declaredColumnObject.setName(UUID.randomUUID().toString());
		selectedColumn = model.getObject().getColumns().get(0);	
						
		add(new Label("name",  new StringResourceModel("CreatePanel.name", this, null)));
		nameText = new TextField<String>("nameText", new PropertyModel<String>(this, "declaredColumnObject.columnName"));
		nameText.add(new AnalysisNameValidator(getString("JcrNameValidator")));
		nameText.setOutputMarkupPlaceholderTag(true);
 		add(nameText);
 		
 		DropDownChoice<String> columnChoice = new DropDownChoice<String>("columnChoice", new PropertyModel<String>(this, "selectedColumn"), model.getObject().getColumns());
		columnChoice.setOutputMarkupPlaceholderTag(true);
		columnChoice.setNullValid(false);	
		columnChoice.add(new AjaxFormComponentUpdatingBehavior("onChange") {
		      @Override
		      protected void onUpdate(AjaxRequestTarget target) {
		    	  selectedColumn = (String) getFormComponent().getConvertedInput();
		      }
		 });
 		add(columnChoice); 
 		
 		final DropDownChoice<String> aggChoice = new DropDownChoice<String>("aggChoice", new PropertyModel<String>(this, "selectedAgg"), DatabaseUtil.aggregates);
 		aggChoice.setOutputMarkupPlaceholderTag(true);
 		aggChoice.setNullValid(true);	
 		// needed for addColumn AjaxLink
 		aggChoice.add(new AjaxFormComponentUpdatingBehavior("onChange") {
 		      @Override
 		      protected void onUpdate(AjaxRequestTarget target) {
 		    	 selectedAgg = (String) getFormComponent().getConvertedInput();
 		      }
 		 });
 		add(aggChoice); 
 		
 		AjaxLink addColumn = new AjaxLink("addColumn") {			
			@Override
			public void onClick(AjaxRequestTarget target) {
				String newText = declaredColumnObject.getExpression();
				if (newText == null) {
					newText = "";
				}							
				if (selectedAgg == null) {
					newText = newText + " " + selectedColumn;
				} else {
					newText = newText + " " + selectedAgg + "(" + selectedColumn + ")";
				}				
				declaredColumnObject.setExpression(newText);	
				target.add(expressionText);				
			} 			
 		};
 		add(addColumn);
 		
 		add(new Label("expression", new StringResourceModel("CreatePanel.expression", this, null)));
		expressionText = new TextArea<String>("expressionText", new PropertyModel<String>(this, "declaredColumnObject.expression"));		
		//expressionText.add(new JcrNameValidator(getString("JcrNameValidator")));
		expressionText.setOutputMarkupPlaceholderTag(true);			
 		add(expressionText); 
 		
 		add(new Label("type", new StringResourceModel("CreatePanel.type", this, null)));
		typeChoice = new DropDownChoice<String>("typeChoice", 
				new PropertyModel<String>(this, "declaredColumnObject.type"),
				DatabaseUtil.getJavaTypes(), 
				new ChoiceRenderer<String>() {
					@Override
					public Object getDisplayValue(String name) {
						int index = name.lastIndexOf(".");
						return name.substring(index+1);
					}
				}	
		);
		typeChoice.setOutputMarkupPlaceholderTag(true);
		typeChoice.setNullValid(false);		
 		add(typeChoice);  		 		
 		
 		AjaxSubmitLink addLink = new AjaxSubmitLink("addLink") {						
 			@Override
 			protected void onSubmit(AjaxRequestTarget target, Form<?> form) { 				
 				if ((declaredColumnObject.getColumnName() == null) || "".equals(declaredColumnObject.getColumnName().trim())) {
 					error(getString("CreatePanel.askName"));
 					target.add(getFeedbackPanel());
        			return;
 				}
 				if ((declaredColumnObject.getExpression() == null) || "".equals(declaredColumnObject.getExpression().trim())) {
 					error(getString("CreatePanel.askExpression"));
 					target.add(getFeedbackPanel());
        			return;
 				}
 				if (editIndex != -1) {
 					int index =  findDeclaredColumnByName(CreatePanel.this.model.getObject().getDeclaredColumns(), declaredColumnObject.getColumnName()); 					
 					if ( (index != -1) && (index != editIndex) ) {
 						error(getString("CreatePanel.duplicateColumn"));	    
	            		target.add(getFeedbackPanel());
	        			return;
 					}
 					 					
 					CreatePanel.this.model.getObject().editDeclaredColumn(editIndex, oldColumnIndex, oldFilterIndex, oldSortIndex, oldGroupIndex, declaredColumnObject.clone());
 					resetEdit(target);
 				} else { 	
 					int index = findDeclaredColumnByName(CreatePanel.this.model.getObject().getDeclaredColumns(), declaredColumnObject.getColumnName());
	 				if (index != -1) {
	 					error(getString("CreatePanel.duplicateColumn"));	    
	            		target.add(getFeedbackPanel());
	        			return;
	 				}
	 				CreatePanel.this.model.getObject().addDeclaredColumn(declaredColumnObject.clone());
	 			} 				
 				target.add(getFeedbackPanel());
 				target.add(table);
 			} 
 			
 			@Override
 			protected void onError(AjaxRequestTarget target, Form<?> form) { 				
 				target.add(getFeedbackPanel());
 			}
 			
 	    };
 	    
 	    addTextModel = Model.of(""); 	    
 	    label = new Label("addMessage", addTextModel);
 	    label.setOutputMarkupPlaceholderTag(true);
 	    addLink.add(label);
 	    add(addLink);
 	    
 	    addTable();
	}	
	
	protected void cancelAdd() {
		if (declaredColumnObject != null) {
			CreatePanel.this.model.getObject().deleteDeclaredColumn(declaredColumnObject);
		}
	}
	
	protected void onConfigure()  {
		super.onConfigure();
		addTextModel.setObject(getString("add"));
    }
	
	private void resetEdit(AjaxRequestTarget target) {
		addTextModel.setObject(getString("add"));
		editIndex = -1;
		oldColumnIndex = -1;
		oldFilterIndex = -1;
		oldSortIndex = -1;
		oldGroupIndex = -1;
		target.add(label);
	}
	
	private void addTable() {
        List<IColumn<AnalysisDeclaredColumn, String>> columns = new ArrayList<IColumn<AnalysisDeclaredColumn, String>>();
        
        columns.add(new AbstractColumn<AnalysisDeclaredColumn, String>(new Model<String>("")) {

            @Override
            public String getCssClass() {
                return "index";
            }

            public void populateItem(Item<ICellPopulator<AnalysisDeclaredColumn>> item, String componentId, final IModel<AnalysisDeclaredColumn> rowModel) {                 
            	int col=item.getIndex();
            	Item<?> i = (Item<?>) item.getParent().getParent();
            	int row = i.getIndex()+1; 
                item.add(new Label(componentId, new Model<String>(String.valueOf(row))));                
            }
        });
        
        columns.add(new AbstractColumn<AnalysisDeclaredColumn, String>(new StringResourceModel("CreatePanel.name", CreatePanel.this, null)) {
            public void populateItem(Item<ICellPopulator<AnalysisDeclaredColumn>> item, String componentId, final IModel<AnalysisDeclaredColumn> rowModel) {
                final AnalysisDeclaredColumn createObject = rowModel.getObject();                
                item.add(new Label(componentId, new Model<String>(createObject.getColumnName())));
            }
        });   
        
        columns.add(new AbstractColumn<AnalysisDeclaredColumn, String>(new StringResourceModel("CreatePanel.expression", CreatePanel.this, null)) {
            public void populateItem(Item<ICellPopulator<AnalysisDeclaredColumn>> item, String componentId, final IModel<AnalysisDeclaredColumn> rowModel) {
                final AnalysisDeclaredColumn createObject = rowModel.getObject();                
                item.add(new Label(componentId, new Model<String>(createObject.getExpression())));
            }
        });   
        
        columns.add(new AbstractColumn<AnalysisDeclaredColumn, String>(new StringResourceModel("CreatePanel.type", CreatePanel.this, null)) {
            public void populateItem(Item<ICellPopulator<AnalysisDeclaredColumn>> item, String componentId, final IModel<AnalysisDeclaredColumn> rowModel) {
                final AnalysisDeclaredColumn createObject = rowModel.getObject();    
                String type = createObject.getType();
                int index = type.lastIndexOf(".");				
                item.add(new Label(componentId, new Model<String>(type.substring(index+1))));
            }
        });                 
        
        columns.add(new LinkPropertyColumn<AnalysisDeclaredColumn>(new StringResourceModel("edit", CreatePanel.this, null), new StringResourceModel("edit", CreatePanel.this, null)) {
			
			private static final long serialVersionUID = 1L;

			@Override
			public void onClick(Item item, String componentId, IModel model, AjaxRequestTarget target) {										
				AnalysisDeclaredColumn declaredColumnObject = (AnalysisDeclaredColumn) model.getObject();	
				editIndex = CreatePanel.this.model.getObject().getDeclaredColumns().indexOf(declaredColumnObject);
				oldColumnIndex = CreatePanel.this.model.getObject().getColumnIndexByName(declaredColumnObject.getExpression() + DatabaseUtil.AS + declaredColumnObject.getColumnName());
				oldFilterIndex = CreatePanel.this.model.getObject().getFilterIndexByName(declaredColumnObject.getColumnName());
				oldSortIndex = CreatePanel.this.model.getObject().getSortIndexByName(declaredColumnObject.getColumnName());
				oldGroupIndex = CreatePanel.this.model.getObject().getGroupIndexByName(declaredColumnObject.getColumnName());
				CreatePanel.this.declaredColumnObject = declaredColumnObject;	
				addTextModel.setObject(getString("edit"));
				target.add(nameText);
				target.add(expressionText);
				target.add(typeChoice);				
				target.add(label);
			}
		});
        
        columns.add(new LinkPropertyColumn<AnalysisDeclaredColumn>(new StringResourceModel("delete", CreatePanel.this, null), new StringResourceModel("delete", CreatePanel.this, null),  new StringResourceModel("CreatePanel.askDelete", CreatePanel.this, null)) {
			
			private static final long serialVersionUID = 1L;

			@Override
			public void onClick(Item item, String componentId, IModel model, AjaxRequestTarget target) {										
				AnalysisDeclaredColumn declaredColumnObject = (AnalysisDeclaredColumn) model.getObject();																																								
				CreatePanel.this.model.getObject().deleteDeclaredColumn(declaredColumnObject);
				resetEdit(target);
				target.add(table);
				onDelete(getAnalysis(), target);                
			}
		});
               
        provider =  new DeclaredColumnObjectDataProvider(model);
        table = new BaseTable<AnalysisDeclaredColumn>("table", columns, provider, 10);
        table.setOutputMarkupId(true);
        add(table);
    }
	
	public AnalysisDeclaredColumn getDeclaredColumnObject() {
		return declaredColumnObject;
	}		
	
	public Analysis getAnalysis() {
		return CreatePanel.this.model.getObject();
	}
	
	public void onDelete(Analysis analysis, AjaxRequestTarget target) {		
	}
	
	private int findDeclaredColumnByName(List<AnalysisDeclaredColumn> list, String columnName) {
		for (int i=0, size=list.size(); i<size; i++) {
			if (list.get(i).getColumnName().equals(columnName)) {
				return i;
			}
		}
		return -1;
	}
	
	public boolean isEdit() {
		return editIndex != -1;
	}

}