package kz.cafe.admin.panels;

import java.text.*;
import java.util.*;
import java.util.regex.*;
import kz.cafe.admin.*;
import kz.cafe.admin.constants.*;
import kz.cafe.admin.constants.AccessConstants.EditMode;
import kz.cafe.admin.hooks.*;
import kz.cafe.admin.panel_extensions.*;
import kz.cafe.admin.panels.components.*;
import kz.cafe.admin.panels.model.*;
import kz.cafe.constants.*;
import kz.cafe.db.*;
import kz.cafe.db.model.*;
import kz.cafe.db.model.anotations.*;
import kz.cafe.logs.*;
import org.apache.commons.logging.*;
import com.google.code.morphia.query.*;
import com.mongodb.*;
import com.vaadin.data.*;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.event.*;
import com.vaadin.terminal.*;
import com.vaadin.ui.*;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.Table.ColumnGenerator;
import com.vaadin.ui.Table.HeaderClickEvent;
import com.vaadin.ui.Window.Notification;
import com.vaadin.ui.themes.*;



public class DBListPanel<T> extends AbstractDBPanel<T> implements java.io.Serializable{
   private static Log log = LogFactory.getLog(MongoService.class);
   private static final String LOG = "[UI] ";







   private static final long serialVersionUID = 1887604984628963165L;


   private volatile boolean NOT_INITED_YET = true;

   private static final String BT_RELOAD  = "Обновить";
   private static final String BT_ADD     = "Добавить";
   private static final String BT_EDIT    = "Редактировать";
   private static final String BT_SAVE    = "Сохранить";
   private static final String BT_CANCEL  = "Отменить";
   private static final String BT_DELETE  = "Удалить";
   
   private static final String CB_DELETED = "Показывать удаленные";
   private static final String BT_UNDELETE  = "Восстановить";

   private static final int SEARCH_PADDING = 50;
   private static final String SEARCH_HEIGHT = "30px";


   private final AdminMain application;


   public final CustomDescriptor descriptor;
   
   public final Set<Integer> setSelectedIDes = new HashSet<Integer>();
   

   private Button   btReload   = new Button(BT_RELOAD);
   
   
   protected Button    btFirst = new Button("<<");
   protected Button    btPrev  = new Button("<");
   protected TextField tfPage  = new TextField();
   protected TextField tfTotal = new TextField();
   protected Button    btGo    = new Button();
   protected Button    btNext  = new Button(">");
   protected Button    btLast  = new Button(">>");
   
   
   private Button   btAdd         = new Button(BT_ADD);
   private Button   btEdit        = new Button(BT_EDIT);
   private Button   btSave        = new Button(BT_SAVE);
   private Button   btCancel      = new Button(BT_CANCEL);
   private Button   btDelete      = new Button(BT_DELETE);
   private CheckBox cbShowDeleted = new CheckBox(CB_DELETED);
   private Button   btUnDelete    = new Button(BT_UNDELETE);

   private boolean isEditMode = false;

   public Object itemId;
   public String sItemId;



   private Map<String, TextField>  mapFilterText            = new HashMap<String, TextField>();
   private Map<String, TextField>  mapFilterLocalizedText   = new HashMap<String, TextField>();
   private Map<String, CheckBox>   mapFilterBooleanTrueOnly = new HashMap<String, CheckBox>();
   private Map<String, TextField>  mapFilterInteger         = new HashMap<String, TextField>();
   private Map<String, ListSelect> mapFilterIntegerSign     = new HashMap<String, ListSelect>();
   private Map<String, DateField>  mapFilterDateFrom        = new HashMap<String, DateField>();
   private Map<String, DateField>  mapFilterDateTo          = new HashMap<String, DateField>();
   private Map<String, Select>     mapFilterSelect          = new HashMap<String, Select>();



   private Map<String, CustomField> mapVirtualFields = new HashMap<String, CustomField>();


   public Table table;
   private Order order;



   private HorizontalLayout panelTopAddons = new HorizontalLayout();
   private HorizontalLayout panelBottomAddons = new HorizontalLayout();
   private List<AbstractExtendedPanel> listExtraPanels = new ArrayList<AbstractExtendedPanel>();


   private final Constraint constraint;


   private final Dimension dim;
   private final Set<EditMode> setMode;
   public  final Set<Integer> setBlockedRecords;



   public MAbstractEditableDataElement oldValueMongoObject = null;
   private Map<String, Object> mapOldValuesInTable = new HashMap<String, Object>();


   private List<IHookAdd>      listHookAdds      = new ArrayList<IHookAdd>();
   private List<IHookEdit>     listHookEdits     = new ArrayList<IHookEdit>();
   private List<IHookDelete>   listHookDeletes   = new ArrayList<IHookDelete>();
   private List<IHookUndelete> listHookUnDeletes = new ArrayList<IHookUndelete>();

   
   
   
   int iCurrentPage;
   int iMaxPages;
   private final int PAGE_SIZE = 50;
   
   
   // Here we keep the edit mode UI elements
   private final Map<String, AbstractField> mapEditModeComponents = new HashMap<String, AbstractField>();
   
   
   private TableFieldFactory factory = new TableFieldFactory(){
      private static final long serialVersionUID = -4593144203144832507L;

      @SuppressWarnings({ "rawtypes" })
      public Field createField(Container container,
                               Object rowInProgressID,
                               Object propertyId,
                               Component uiContext){

         //Let's go in for Virtual fields first
         CustomField cstField = mapVirtualFields.get(propertyId.toString());
         if(cstField != null){
            if(isEditMode){
               if(itemId == rowInProgressID){
                  if(cstField.isEditable) {
                     return new CheckBox();
                  }
               }
            }

            return null;
         }


         cstField = descriptor.mapNames.get(propertyId.toString());
         java.lang.reflect.Field field = getField(cstField.db);

         String sField = field.toString().toLowerCase();

         if(isEditMode && cstField.isEditable){
            if(("" + itemId).equals("" + rowInProgressID)){
               if(cstField instanceof FCustomController){
                  CheckBox cbController = new CheckBox();
                  cbController.setImmediate(true);
                  cbController.addListener(new LController((FCustomController) cstField));
                  mapEditModeComponents.put(cstField.name, cbController);
                  return cbController;
               }
               else if(sField.contains("bool")){
                  CheckBox cb = new CheckBox();
                  mapEditModeComponents.put(cstField.name, cb);
                  return cb;
               }
               else if(field.isAnnotationPresent(AnnotationDate.class) ){
                  CustomDateField cdf = (CustomDateField) cstField;

                  DateField df = new DateField();
                  df.setWidth(cstField.style.width + "px");
                  df.setDateFormat(cdf.format);
                  
                  mapEditModeComponents.put(cstField.name, df);
                  return df;
               }
               else if(field.isAnnotationPresent(AnnotationTime.class) ){
                  TextField tf = new TextField();
                  //tf.setWidth(cstField.style.width + "px");

                  tf.setWidth("42px");
                  tf.setHeight("24px");
                  tf.setMaxLength(5);
                  tf.setStyleName("no-textarea-resize");

                  mapEditModeComponents.put(cstField.name, tf);
                  return tf;
               }
               else if(field.isAnnotationPresent(AnnotationPrice.class) ){
                  TextField tf = new TextField();
                  tf.setWidth(cstField.style.width + "px");

                  //tf.setWidth("42px");
                  tf.setHeight("24px");
                  tf.setStyleName("no-textarea-resize");

                  mapEditModeComponents.put(cstField.name, tf);
                  return tf;
               }
               
               
               
               else if(cstField instanceof CustomFixedComboField){
                  // TODO

                  CustomFixedComboField cdf = (CustomFixedComboField) cstField;


                  Select select = new Select();

                  if(field.isAnnotationPresent(AnnotationRelated.class) ){
                     Class classForeign =
                              field.getAnnotation(AnnotationRelated.class).foreign();

                     localizeCombos(cdf, classForeign);
                  }

                  for(CustomFixedComboField.Element elem : cdf.getElements()){
                     select.addItem(elem.text);
                  }


                  select.setNullSelectionAllowed(!cdf.isMust);

                  select.setWidth(cstField.style.width + "px");
                  select.setHeight("24px");

                  mapEditModeComponents.put(cstField.name, select);
                  return select;
               }
               
               
               
               else if(cstField instanceof CustomDatabaseComboField){
                  // TODO

                  CustomDatabaseComboField cdf = (CustomDatabaseComboField) cstField;


                  Select select = new Select();

                  if(field.isAnnotationPresent(AnnotationRelated.class) ){
                     Class classForeign =
                              field.getAnnotation(AnnotationRelated.class).foreign();

                     localizeCombos(cdf, classForeign);
                  }

                  for(CustomFixedComboField.Element elem : cdf.getElements()){
                     select.addItem(elem.text);
                  }


                  select.setNullSelectionAllowed(!cdf.isMust);

                  select.setWidth(cstField.style.width + "px");
                  select.setHeight("24px");

                  mapEditModeComponents.put(cstField.name, select);
                  return select;
               }
               

               
               
               else if(cstField instanceof CustomMultiCombo){
                  CustomMultiCombo cdf = (CustomMultiCombo) cstField;
                  
                  switch (cdf.type){
                     case COMBO:{
                        Select select = new Select();
                        select.setNullSelectionAllowed(!cdf.isMust);
                        select.setMultiSelect(true);

                        select.setWidth(cstField.style.width + "px");
                        select.setHeight(cstField.style.height + "px");
                        

                        Class classForeign = field.getAnnotation(AnnotationIncusiveList.class).foreign();

                        localizeCombos(cdf, classForeign);

                        
                        
                        for(CustomFixedComboField.Element elem : cdf.getElements()){
                           select.addItem(elem.text);
                           select.select(elem.text);
                        }
                        

                        
                        
//                        Object objValue = table.getItem(itemId).getItemProperty(cstField.name);
//                        String sAllInLine = "" + objValue;
//                        
//                        String[] arrstrValues = sAllInLine.split(",");
//                        
//                        for(String sValue : arrstrValues){
//                           select.select(sValue);
//                        }

                        mapEditModeComponents.put(cstField.name, select);
                        return select;
                     }
                  }
               }
               
               
               
               
               
               else if(field.isAnnotationPresent(AnnotationImage.class) ){

                  //We do not edit image in table
                  return null;
               }
               else{
                  TextField tf = new TextField();
                  tf.setHeight("24px");
                  tf.setWidth("100%");
                  
                  if(cstField.style.height > 0) {
                     tf.setHeight(cstField.style.height + "px");
                  }

                  if(cstField.style.expandable) {
                  }
                  else{
                     tf.setStyleName("no-textarea-resize");
                  }

                  mapEditModeComponents.put(cstField.name, tf);
                  return tf;
               }
            }
            
            //Let's check the controllers
            for(CustomField cstFieldController : descriptor.listFields){
               if(cstFieldController instanceof FCustomController){
                  FCustomController fController = (FCustomController) cstFieldController;
                  
                  boolean bController = Boolean.parseBoolean("" + table.getItem(table.getValue()).getItemProperty(cstFieldController.name).getValue());
                  
                  for(String sTableFieldName : fController.listFields){
                     AbstractComponent abstractComponent = mapEditModeComponents.get(sTableFieldName); 
                     
                     if(abstractComponent == null) {
                        //not loaded yet, will be process by Vaadin later
                     }
                     else{
                        abstractComponent.setEnabled(bController);
                     }
                  }
               }
            }
         }
         else{
            // It's RO mode
            //System.out.println(cstField);

            try{
               if(field.isAnnotationPresent(AnnotationRelated.class)){
                  AnnotationRelated annotationRelated = field.getAnnotation(AnnotationRelated.class);

                  //String sRelatedFieldName = descriptor.mapDBFields.get(field.getName()).name;

                  int ID;

                  if(cstField instanceof CustomRelationField){
                     CustomRelationField crf = (CustomRelationField) cstField;
                     ID = Integer.parseInt("" + table.getItem(rowInProgressID).getItemProperty(crf.relationField));
                  }
                  else if(cstField instanceof CustomFixedComboField){
                     CustomFixedComboField ccf = (CustomFixedComboField) cstField;
                     ID = ccf.get("" + table.getItem(rowInProgressID).getItemProperty(propertyId)).id;
                  }
                  else if(cstField instanceof CustomDatabaseComboField){
                     CustomDatabaseComboField ccf = (CustomDatabaseComboField) cstField;
                     ID = ccf.get("" + table.getItem(rowInProgressID).getItemProperty(propertyId)).id;
                  }
                  else{
                     return null;
                  }


                  //int ID = Integer.parseInt("" + table.getItem(rowInProgressID).getItemProperty(sRelatedFieldName));

                  RelationButton bt = new RelationButton(application,
                                                         ID,
                                                         application.mapMenuClass.get(annotationRelated.foreign()).abstractTab,
                                                         application.mapMenuClass.get(annotationRelated.foreign()).name);
                  bt.addStyleName(BaseTheme.BUTTON_LINK);
                  return bt;
               }
               else if(cstField instanceof CustomRelationFieldFlexable){
                  CustomRelationFieldFlexable cdf = (CustomRelationFieldFlexable) cstField;

                  int ID = Integer.parseInt("" + table.getItem(rowInProgressID).getItemProperty(cdf.relationField));
                  Class classEntity = Class.forName("" + table.getItem(rowInProgressID).getItemProperty(cdf.sRelatedClassField));

                  RelationButton bt = new RelationButton(application,
                                                         ID,
                                                         application.mapMenuClass.get(classEntity).abstractTab,
                                                         application.mapMenuClass.get(classEntity).name);
                  bt.addStyleName(BaseTheme.BUTTON_LINK);
                  return bt;
               }
            }
            catch (Throwable e){
            }
         }

         return null;
      }
   };








   public DBListPanel(AdminMain application,
                      Class<T> classDB,
                      final CustomDescriptor descriptor,
                      Dimension dim,
                      Set<EditMode> setMode){

      this.classDB = classDB;
      this.application = application;
      this.descriptor = descriptor;
      this.dim = dim;
      this.setBlockedRecords = new HashSet<Integer>();

      int iHeight = 26;
      for(CustomField customField : descriptor.listFields) {
         if(customField.style.height > iHeight) {
            iHeight = customField.style.height;
         }
      }
      this.setMode = setMode;
      this.constraint = new Constraint();

      init();
   }





   public DBListPanel(AdminMain application,
                      Class<T> classDB,
                      final CustomDescriptor descriptor,
                      Dimension dim,
                      Set<EditMode> setMode,
                      Order order){

      this.classDB = classDB;
      this.application = application;
      this.descriptor = descriptor;
      this.dim = dim;
      this.setBlockedRecords = new HashSet<Integer>();
      this.order = order;

      int iHeight = 26;
      for(CustomField customField : descriptor.listFields){
         if(customField.style.height > iHeight){
            iHeight = customField.style.height;
         }
      }
      this.setMode = setMode;
      this.constraint = new Constraint();

      init();
   }





   public DBListPanel(AdminMain application,
                      Class<T> classDB,
                      final CustomDescriptor descriptor,
                      Dimension dim,
                      Set<EditMode> setMode,
                      Constraint constraint){
      this.classDB = classDB;
      this.application = application;
      this.descriptor = descriptor;
      this.dim = dim;
      this.setMode = setMode;
      this.constraint = constraint;
      this.setBlockedRecords = new HashSet<Integer>();

      init();
   }







   public DBListPanel(AdminMain application,
                      Class<T> classDB,
                      final CustomDescriptor descriptor,
                      Dimension dim,
                      Set<EditMode> setMode,
                      Constraint constraint,
                      Order order){
      this.classDB = classDB;
      this.application = application;
      this.descriptor = descriptor;
      this.dim = dim;
      this.setMode = setMode;
      this.constraint = constraint;
      this.setBlockedRecords = new HashSet<Integer>();
      this.order = order;

      init();
   }









   public DBListPanel(AdminMain application,
                      Class<T> classDB,
                      final CustomDescriptor descriptor,
                      Dimension dim,
                      Set<EditMode> setMode,
                      Constraint constraint,
                      Set<Integer> setBlockedRecords){

      this.classDB = classDB;
      this.application = application;
      this.descriptor = descriptor;
      this.dim = dim;
      this.setMode = setMode;
      this.constraint = constraint;
      this.setBlockedRecords = setBlockedRecords;

      init();
   }


   
   
   
   
   
   
   



   @SuppressWarnings({ "rawtypes", "unchecked" })
   public void init(){
      this.table = new ExtendedTable(descriptor);


      //Let's do some table calculation
      int iHeight = dim.iHeight;

      //menu
      iHeight -= 110;

      //No edit panel at all
      if(setMode.size() == 0){
         iHeight += 30;
      }


      int iMaxSearchRow = 0;
      for(Integer iRow : descriptor.mapSearchOrder.keySet()){
         if(iRow > iMaxSearchRow){
            iMaxSearchRow = iRow;
         }
      }

      iHeight -= ((iMaxSearchRow + 1) * 35);

      //this.setWidth("" + dim.iWidth + "px");
      //this.setHeight("" + iHeight + "px");


      table.setSizeFull();
      //table.setWidth("" + (dim.iWidth + 40) + "px");
      //table.setPageLength(new Double(iHeight / (ROW_HEIGHT * 3)).intValue());
      table.setCacheRate(10);
      table.setHeight(iHeight + "px");




      VerticalLayout layout = (VerticalLayout) getContent();
      layout.setMargin(false);
      layout.setSpacing(false);

      this.addComponent(sizeY(5, "panel-header"));

      table.setColumnCollapsingAllowed(true);


      table.setSelectable(true);
      table.setSortDisabled(true);
      table.setTableFieldFactory(factory);
      table.setEditable(true);
      table.setImmediate(true);

      table.addListener(new LTable());
      table.addListener(new LHeader());
      table.addListener(new LTableNavigation());




      HorizontalLayout layTop = new HorizontalLayout();
      layTop.setWidth("100%");
      VerticalLayout layTopFilter = new VerticalLayout();
      HorizontalLayout layFilter = new HorizontalLayout();
      layFilter.setHeight(SEARCH_HEIGHT);
      layFilter.addComponent(sizeX(5));

      CURRENT_LANG.addListener(new LLangChange());

      layFilter.addComponent(new Label("Язык:"));
      layFilter.addComponent(sizeX(5));
      layFilter.addComponent(CURRENT_LANG);
      layFilter.addComponent(sizeX(SEARCH_PADDING));

      //TODO
      for(int i = 0; i < descriptor.mapSearchOrder.keySet().size(); i++) {
         List<CustomField> list = descriptor.mapSearchOrder.get(i);

         if(list == null){
            continue;
         }

         for(CustomField cstField : list){
            java.lang.reflect.Field field = getField(cstField.db);

            if(field.isAnnotationPresent(AnnotationIncusiveList.class) ){
               Class classDescriptor = field.getAnnotation(AnnotationIncusiveList.class).foreign();

               for(MAbstractDescriptor mAbstractDesriptor :
                           (List<MAbstractDescriptor>) MongoService.getList(classDescriptor)){

                  switch(cstField.search.mode){
                     case BOOLEAN_ONLY_TRUE:{
                        CheckBox cb = new CheckBox();
                        cb.setImmediate(true);
                        cb.addListener(new LChangeFilter());
                        mapFilterBooleanTrueOnly.put(cstField.db + "." + mAbstractDesriptor.ID, cb);

                        layFilter.addComponent(new Label(mAbstractDesriptor.name.get(InterfaceConstants.LANGS.RU) + ":"));
                        layFilter.addComponent(sizeX(5));

                        layFilter.addComponent(cb);
                        layFilter.addComponent(sizeX(SEARCH_PADDING));
                        break;
                     }
                  }
               }
            }
            else{
               if(cstField instanceof CustomFixedComboField){

                  CustomFixedComboField cdf = (CustomFixedComboField) cstField;


                  Select select = new Select();

                  if(field.isAnnotationPresent(AnnotationRelated.class) ){
                     Class classForeign =
                              field.getAnnotation(AnnotationRelated.class).foreign();

                     localizeCombos(cdf, classForeign);
                  }

                  for(CustomFixedComboField.Element elem : cdf.getElements()){
                     select.addItem(elem.text);
                  }


                  select.setImmediate(true);
                  select.addListener(new LChangeFilter());
                  select.setNullSelectionAllowed(true);
                  mapFilterSelect.put(cstField.db, select);


                  select.setWidth(cstField.style.width + "px");
                  select.setHeight("24px");

                  layFilter.addComponent(new Label(cstField.name + ":"));
                  layFilter.addComponent(sizeX(5));
                  layFilter.addComponent(select);
                  layFilter.addComponent(sizeX(SEARCH_PADDING));
               }
               if(cstField instanceof CustomDatabaseComboField){

                  CustomDatabaseComboField cdf = (CustomDatabaseComboField) cstField;


                  Select select = new Select();

                  if(field.isAnnotationPresent(AnnotationRelated.class) ){
                     Class classForeign =
                              field.getAnnotation(AnnotationRelated.class).foreign();

                     localizeCombos(cdf, classForeign);
                  }

                  for(CustomFixedComboField.Element elem : cdf.getElements()){
                     select.addItem(elem.text);
                  }


                  select.setImmediate(true);
                  select.addListener(new LChangeFilter());
                  select.setNullSelectionAllowed(true);
                  mapFilterSelect.put(cstField.db, select);


                  select.setWidth(cstField.style.width + "px");
                  select.setHeight("24px");

                  layFilter.addComponent(new Label(cstField.name + ":"));
                  layFilter.addComponent(sizeX(5));
                  layFilter.addComponent(select);
                  layFilter.addComponent(sizeX(SEARCH_PADDING));
               }
               else{
                  switch(cstField.search.mode){
                     case INTEGER:{
                        HorizontalLayout layH = new HorizontalLayout();

                        layH.addComponent(new Label(cstField.name + ":"));
                        layH.addComponent(sizeX(5));

                        ListSelect select = new ListSelect();
                        select.setImmediate(true);
                        select.addListener(new LChangeFilter());
                        select.setWidth("40px");
                        select.setNullSelectionAllowed(false);
                        select.setRows(1);
                        select.addItem("=");
                        select.addItem("<");
                        select.addItem(">");
                        select.select(select.getItemIds().iterator().next());

                        mapFilterIntegerSign.put(cstField.db, select);

                        layH.addComponent(select);

                        TextField tf = new TextField();
                        tf.setImmediate(true);
                        tf.addListener(new LChangeFilter());
                        tf.setWidth("80px");
                        mapFilterInteger.put(cstField.db, tf);
                        layH.addComponent(tf);

                        layFilter.addComponent(layH);
                        layFilter.addComponent(sizeX(SEARCH_PADDING));
                        break;
                     }

                     case BOOLEAN:{
                        ListSelect select = new ListSelect(cstField.name);
                        select.setImmediate(true);
                        select.addListener(new LChangeFilter());
                        select.setWidth("60px");
                        select.setNullSelectionAllowed(true);
                        select.setRows(1);
                        select.addItem("да");
                        select.addItem("нет");
                        // mapFilterSelect.put(field.db, select);
                        layFilter.addComponent(select);
                        layFilter.addComponent(sizeX(SEARCH_PADDING));
                        break;
                     }
                     case BOOLEAN_ONLY_TRUE:{
                        CheckBox cb = new CheckBox();
                        cb.setImmediate(true);
                        cb.addListener(new LChangeFilter());
                        mapFilterBooleanTrueOnly.put(cstField.db, cb);

                        layFilter.addComponent(new Label(cstField.name + ":"));
                        layFilter.addComponent(sizeX(5));

                        layFilter.addComponent(cb);
                        layFilter.addComponent(sizeX(SEARCH_PADDING));
                        break;
                     }

                     case TIME_RANGE:{
                        HorizontalLayout layH = new HorizontalLayout();

                        NativeSelect selHours = new NativeSelect();
                        for(int f = 0; f < 24; f++){
                           selHours.addItem(f);
                        };
                        // selHours.setWidth("80px");
                        layH.addComponent(selHours);

                        // layH.addComponent(sizeX(5));

                        NativeSelect selMinutes = new NativeSelect();
                        for(int f = 0; f < 59; f++){
                           selMinutes.addItem(f);
                        };
                        // selMinutes.setWidth("40px");
                        layH.addComponent(selMinutes);

                        layFilter.addComponent(new Label(cstField.name + ":"));
                        layFilter.addComponent(sizeX(5));

                        layFilter.addComponent(layH);
                        layFilter.addComponent(sizeX(SEARCH_PADDING));

                        break;
                     }

                     case DATE_RANGE:{
                        CustomDateField cdf = (CustomDateField) cstField;

                        HorizontalLayout layH = new HorizontalLayout();
                        //layH.setWidth("200px");
                        DateField dfFrom = new DateField();
                        dfFrom.setDateFormat("HH:mm dd.MM.yyyy");
                        dfFrom.setImmediate(true);
                        dfFrom.setWidth("90px");
                        dfFrom.addListener(new LChangeFilter());

                        layH.addComponent(new Label(cstField.name + ":"));
                        layH.addComponent(sizeX(5));
                        layH.addComponent(dfFrom);
                        mapFilterDateFrom.put(cdf.db, dfFrom);

                        layH.addComponent(sizeX(5));

                        DateField dfTo = new DateField();
                        dfTo.setDateFormat("HH:mm dd.MM.yyyy");
                        dfTo.setImmediate(true);
                        dfTo.setWidth("90px");
                        dfTo.addListener(new LChangeFilter());
                        layH.addComponent(new Label("<div style=\"font-size:8px;padding-top:3px\">X</div>", Label.CONTENT_XHTML));
                        layH.addComponent(sizeX(5));
                        layH.addComponent(dfTo);
                        layFilter.addComponent(layH);
                        mapFilterDateTo.put(cdf.db, dfTo);
                        layFilter.addComponent(sizeX(SEARCH_PADDING));
                        break;
                     }
                     case STRING:{
                        layFilter.addComponent(new Label(cstField.name + ":"));
                        layFilter.addComponent(sizeX(5));


                        TextField tf = new TextField();
                        tf.setImmediate(true);
                        tf.addListener(new LChangeFilter());
                        tf.setWidth("100%");
                        mapFilterText.put(cstField.db, tf);
                        layFilter.addComponent(tf);
                        layFilter.addComponent(sizeX(SEARCH_PADDING));
                        break;
                     }
                     case LOCALIZED_STRING:{
                        layFilter.addComponent(new Label(cstField.name + ":"));
                        layFilter.addComponent(sizeX(5));

                        TextField tf = new TextField();
                        tf.setImmediate(true);
                        tf.addListener(new LChangeFilter());
                        tf.setWidth("100%");
                        mapFilterLocalizedText.put(cstField.db, tf);
                        layFilter.addComponent(tf);
                        layFilter.addComponent(sizeX(SEARCH_PADDING));
                        break;
                     }
                  }
               }
            }
         }

         layTopFilter.addComponent(layFilter);
         layFilter = new HorizontalLayout();
         layFilter.setHeight(SEARCH_HEIGHT);
         layFilter.addComponent(sizeX(5));
      }


      layTop.addComponent(layTopFilter);

      panelTopAddons.setMargin(false);
      layTop.addComponent(panelTopAddons);

      layTop.setStyleName("panel-header");
      layTop.setExpandRatio(layTopFilter, 20.0f);
      layTop.setExpandRatio(panelTopAddons, 0.1f);


      layTop.setMargin(false);
      this.addComponent(layTop);



      //sdfskdfksdkfpsf
      //sodfiosjdfoisdf





      for(CustomField cstField : descriptor.listFields){
         java.lang.reflect.Field field = getField(cstField.db);
         String sClassName = field.getGenericType().toString().toLowerCase();

         if(field.isAnnotationPresent(AnnotationDate.class) ){
            table.addContainerProperty(cstField.name, Date.class, null);
         }
         if(field.isAnnotationPresent(AnnotationTime.class) ){
            table.addContainerProperty(cstField.name, String.class, null);
         }
         else if(field.isAnnotationPresent(AnnotationIncusiveList.class) ){
            
            CustomMultiCombo cmc = (CustomMultiCombo) cstField;
            
            switch(cmc.type){
               case COMBO:{
                  //Text version, just text
                  table.addContainerProperty(cstField.name, Object.class, null);
                  break;
               }
               default:{
                  //Table with rows
                  Class classDescriptor = field.getAnnotation(AnnotationIncusiveList.class).foreign();

                  for(MAbstractDescriptor mAbstractDesriptor :
                     (List<MAbstractDescriptor>) MongoService.getList(classDescriptor)){

                      String sField = mAbstractDesriptor.name.get(InterfaceConstants.LANGS.RU);

                      table.addContainerProperty(sField, Boolean.class, null);

                      mapVirtualFields.put(sField, cstField);

                      if(cstField.style.width > 0){
                         table.setColumnWidth(sField, cstField.style.width);
                      }
                  }
                  break;
               }
            }
         }
         else if(field.isAnnotationPresent(AnnotationIncusiveListManual.class)){
            CustomFixedComboField ccf = (CustomFixedComboField) cstField;

            for(CustomFixedComboField.Element element : ccf.getElements()){

                String sField = element.text;

                table.addContainerProperty(sField, Boolean.class, null);

                mapVirtualFields.put(sField, cstField);

                if(cstField.style.width > 0){
                   table.setColumnWidth(sField, cstField.style.width);
                }
            }
         }
         else if(cstField instanceof CustomFixedComboField){
            // TODO

            CustomFixedComboField cdf = (CustomFixedComboField) cstField;

            table.addContainerProperty(cstField.name, String.class, null);

            if(cdf.type == CustomFixedComboField.TYPE.TEXT){
            }
            else if(cdf.type == CustomFixedComboField.TYPE.IMAGE){
               final ColumnGenerator generator = new ColumnGenerator(){
                  private static final long serialVersionUID = -8477027423194414697L;

                  @Override
                  public Component generateCell(Table source, Object itemId, Object columnId){
                     String sField = "" + columnId;

                     CustomFixedComboField ccf =
                              (CustomFixedComboField) descriptor.mapNames.get(sField.substring(0, sField.length() - 1));

                     Object objValue = table.getItem(itemId).getItemProperty(ccf.name).getValue();

                     try{
                        return new Label(ccf.get("" + objValue).image, Label.CONTENT_XHTML);
                     }
                     catch (Exception e){
                        return new Label("");
                     }
                  }
               };
               table.addGeneratedColumn(cstField.name + " ", generator);
               table.setColumnAlignment(cstField.name + " ", Table.ALIGN_CENTER);
               table.setColumnWidth(cstField.name + " ", cstField.style.width);
            }
         }
         else if(field.isAnnotationPresent(AnnotationImage.class) ){
            CustomImageField cdf = (CustomImageField) cstField;

            if(cdf.isImageInTable){
               table.addContainerProperty(cstField.name, Label.class, null);
            }
            else{
               table.addContainerProperty(cstField.name, String.class, null);
               try{
                  table.setColumnCollapsed(cstField.name, true);
               }
               catch (Throwable e){
               }
            }
         }
         else if(field.isAnnotationPresent(AnnotationPrice.class) ){
            table.addContainerProperty(cstField.name, String.class, null);
         }
         else if(sClassName.contains("integer")){
            table.addContainerProperty(cstField.name, String.class, null);
         }
         else if(sClassName.contains("long")){
            table.addContainerProperty(cstField.name, String.class, null);
         }
         else if(sClassName.contains("bool")){
            table.addContainerProperty(cstField.name, Boolean.class, null);
         }
         else if(sClassName.contains("float")){
            table.addContainerProperty(cstField.name, Float.class, null);
         }
         else if(sClassName.contains("double")){
            table.addContainerProperty(cstField.name, Double.class, null);
         }
         else{
            table.addContainerProperty(cstField.name, String.class, null);
         }
         
         switch(cstField.style.alignment){
            case LEFT:{
               table.setColumnAlignment(cstField.name, Table.ALIGN_LEFT);
               break;
            }
            case RIGHT:{
               table.setColumnAlignment(cstField.name, Table.ALIGN_LEFT);
               break;
            }
            default:{
               table.setColumnAlignment(cstField.name, Table.ALIGN_CENTER);
               break;
            }
         }
         

         // else if(field.isAnnotationPresent(MultiLangString.class) ){
         //
         // for(InterfaceConstants.LANGS lang :
         // InterfaceConstants.LANGS.values()) {
         // table.addContainerProperty(cstField.name + " (" + lang + ")",
         // Double.class, null);
         // }
         // }
         // else{
         // table.addContainerProperty(cstField.name, String.class, null);
         // }

         if(cstField.style.width > 0){
            table.setColumnWidth(cstField.name, cstField.style.width);
         }

         if(cstField.visible){
         }
         else{
            try{
               table.setColumnCollapsed(cstField.name, true);
            }
            catch (Throwable e){
            }
         }
      }




      table.setCellStyleGenerator(new Table.CellStyleGenerator(){
         private static final long serialVersionUID = 5026899277989475366L;
         @Override
         public String getStyle(Object itemId, Object propertyId){
            if(propertyId == null){
               // Styling for row

               if(setBlockedRecords.contains(itemId)){
                   return "highlight-blocked";
               }
               else{
                   return null;
               }

//               Item item = table.getItem(itemId);
//               String firstName = (String) item.getItemProperty("First Name").getValue();
//               if(firstName.toLowerCase().startsWith("g")){
//                  return "highlight-green";
//               }
//               else if(firstName.contains("o")){
//                  return "highlight-red";
//               }
//               else{
//                  return null;
//               }
            }
            else{
               // styling for column propertyId
               return null;
            }
         }
      });






      // Default Sort Order
      if(order == null) {
         CustomField customField = descriptor.listFields.get(0);
         order = new Order(Order.CREATER, customField.db, customField.name);
      }

      this.addComponent(table);

      this.addComponent(sizeY(10));

      HorizontalLayout layHBottomButtons = new HorizontalLayout();
      
      layHBottomButtons.addComponent(sizeX(5));
      
      
      
      
      btFirst.addListener(new LFirst());
      btPrev.addListener(new LPrev());
      tfPage.setEnabled(false);
      tfPage.setWidth("40px");
      tfTotal.setEnabled(false);
      tfTotal.setWidth("40px");
      
      btGo.setIcon(new ThemeResource("enter.png"));
      //btGo.addStyleName(BaseTheme.BUTTON_LINK);      
      
      btGo.addListener(new LChangePage());
      btNext.addListener(new LNext());
      btLast.addListener(new LLast());

      
      layHBottomButtons.addComponent(btFirst);
      layHBottomButtons.addComponent(sizeX(5));
      layHBottomButtons.addComponent(btPrev);
      layHBottomButtons.addComponent(sizeX(5));
      layHBottomButtons.addComponent(tfPage);
      layHBottomButtons.addComponent(sizeX(5));
      layHBottomButtons.addComponent(tfTotal);
      layHBottomButtons.addComponent(sizeX(5));
      layHBottomButtons.addComponent(btGo);
      layHBottomButtons.addComponent(sizeX(5));
      layHBottomButtons.addComponent(btNext);
      layHBottomButtons.addComponent(sizeX(5));
      layHBottomButtons.addComponent(btLast);
      layHBottomButtons.addComponent(sizeX(20));
      
      
      
      
      
      btReload.addListener(new ClickListener(){
         private static final long serialVersionUID = -2584869015591888148L;

         @Override
         public void buttonClick(ClickEvent event){
            //Let's clean cache
            Caching.clean();
            
            reload();
         }
      });
      layHBottomButtons.addComponent(btReload);
      layHBottomButtons.addComponent(sizeX(10));
      
      

      btAdd.addListener(new ClickListener(){
         private static final long serialVersionUID = -8451527793751514391L;

         @Override
         public void buttonClick(com.vaadin.ui.Button.ClickEvent arg0){
            Object obj = addNewRecordToDB();

            int iNewRecordID = insertEmptyRecord(obj);


            itemId = iNewRecordID;
            sItemId = "" + itemId;


            table.setCurrentPageFirstItemIndex(table.size());
            table.select(iNewRecordID);

            switchToEditMode();
         }
      });
      if(setMode.contains(AccessConstants.EditMode.ADD)){
         layHBottomButtons.addComponent(btAdd);
      }
      layHBottomButtons.addComponent(sizeX(5));




      btEdit.addListener(new ClickListener(){
         private static final long serialVersionUID = -5176789668185463994L;
         @Override
         public void buttonClick(com.vaadin.ui.Button.ClickEvent arg0){
            switchToEditMode();
         }
      });
      if(setMode.contains(AccessConstants.EditMode.CHANGE)){
         layHBottomButtons.addComponent(btEdit);
      }





      layHBottomButtons.addComponent(btSave);
      btSave.addListener(new ClickListener(){
         private static final long serialVersionUID = -5176789668185463994L;
         @Override
         public void buttonClick(com.vaadin.ui.Button.ClickEvent arg0){
            //Let's clean cache
            Caching.clean();
            
            if(saveChanges()){
               switchToReadMode();
            }
         }
      });
      layHBottomButtons.addComponent(btSave);




      layHBottomButtons.addComponent(sizeX(5));





      btCancel.addListener(new ClickListener(){
         private static final long serialVersionUID = -5176789668185463994L;
         @Override
         public void buttonClick(com.vaadin.ui.Button.ClickEvent arg0){
            cancelChanges();
            switchToReadMode();
         }
      });
      layHBottomButtons.addComponent(btCancel);






      //delete button
      if(setMode.contains(AccessConstants.EditMode.DELETE)){
         btDelete.addListener(new ClickListener(){
            private static final long serialVersionUID = -4879909695860169610L;
   
            @Override
            public void buttonClick(com.vaadin.ui.Button.ClickEvent arg0){
               //Let's clean cache
               Caching.clean();
               
               int ID = (Integer) table.getValue();
               deleteRecord((Integer) table.getValue());
   
               table.removeItem(ID);
   
               if(ID > 1){
                  itemId = (ID - 1);
                  sItemId = "" + itemId;
               }
   
               validateButtons();
            }
         });
         layHBottomButtons.addComponent(btDelete);
      }
      


      
      panelBottomAddons.setMargin(false);
      layHBottomButtons.addComponent(panelBottomAddons);
      
      
      //Let's inject default publish/unpublish here
      CustomField customField = descriptor.mapDBFields.get(MAbstractEditableDataElement.F_PUBLISHED);
      
      if(customField == null){
      }
      else{
         panelBottomAddons.addComponent(sizeX(5));
         panelBottomAddons.addComponent(new ExtraPanelPublishAll(this));
         panelBottomAddons.addComponent(sizeX(5));
         panelBottomAddons.addComponent(new ExtraPanelUnPublishAll(this));
      }      
      

      
      
      if(application.isAdmin){
         btUnDelete.addListener(new ClickListener(){

            private static final long serialVersionUID = 8384979999347976522L;

            @Override
            public void buttonClick(ClickEvent event){
               MongoService.undelete(classDB, (int) itemId);
               table.removeItem(itemId);
            }
         });
         layHBottomButtons.addComponent(btUnDelete);
         
         
         
         layHBottomButtons.addComponent(sizeX(20));

         cbShowDeleted.setImmediate(true);
         cbShowDeleted.addListener(new ClickListener(){
            private static final long serialVersionUID = 8384979999347976522L;

            @Override
            public void buttonClick(ClickEvent event){
               validateButtons();
               reload();
            }
         });
         layHBottomButtons.addComponent(cbShowDeleted);
      }

      
      layHBottomButtons.setHeight("30px");
      
      if(!application.isAdmin && setMode.size() == 0){
         //no edit panel at all
      }
      else{
         this.addComponent(layHBottomButtons);
      }

      NOT_INITED_YET = false;


      table.setTableFieldFactory(factory);
      table.setEditable(true);
      table.setImmediate(true);


      switchToReadMode();

      //Initialization end
   }






   boolean bRecordHasBeenFound = false;
   int iRecordOrder = 0;

   public int reload(){
      if(NOT_INITED_YET){
         return 1;
      }
      
      long lStartTime = System.currentTimeMillis();
      log.info(LOG + "Page reload: " + classDB.getName());

      
      grabSelectedIDes();      
      

      table.removeAllItems();

      bRecordHasBeenFound = false;
      iRecordOrder = 0;


      //TODO
      Query<?> query = MongoService.ds
                                   .find(classDB)
                                   .order(order.toMongo());
      
      if(cbShowDeleted.booleanValue()){
         query.filter(MAbstractEditableDataElement.F_DELETED, true);
      }
      else{
         query.filter(MAbstractEditableDataElement.F_DELETED, false);
      }
      

      //Constraints
      for(Constraint.Criterion criterion : constraint.criteria){
         query.filter(criterion.field, criterion.value);
      }


      for(String sField : mapFilterSelect.keySet()){
         Object value = mapFilterSelect.get(sField).getValue();

         if(value == null || "".equals(value)){
         }
         else{
            AbstractComboField ccf = (AbstractComboField) descriptor.mapDBFields.get(sField);

            query.filter(sField, ccf.get("" + value).id);
         }
      }



      for(String sField : mapFilterInteger.keySet()){
         java.lang.reflect.Field classField = getField(sField);
         String sClassFieldType = classField.toString();

         try{
            Object obj;
            if(sClassFieldType.contains("float")) {
               obj = Float.parseFloat("" + mapFilterInteger.get(sField).getValue());
            }
            if(sClassFieldType.contains("double")) {
               obj = Double.parseDouble("" + mapFilterInteger.get(sField).getValue());
            }
            else{

               if(classField.isAnnotationPresent(AnnotationPrice.class) ) {
                  obj = (int) (Float.parseFloat("" + mapFilterInteger.get(sField).getValue()) * 100);
               }
               else {
                  obj = Integer.parseInt("" + mapFilterInteger.get(sField).getValue());
               }
            }

            query.filter(sField + " " + mapFilterIntegerSign.get(sField), obj);
         }
         catch (NumberFormatException e){
            //non integer value
         }
      }



      for(String sField : mapFilterLocalizedText.keySet()){
         Object sValue = "" + mapFilterLocalizedText.get(sField).getValue();

         if(sValue == null || "".equals(sValue)){
         }
         else{
//            Pattern regexp = Pattern.compile("" + sValue, Pattern.CASE_INSENSITIVE);
//            query.filter(sField + "." + CURRENT_LANG.getValue(), regexp);

            Pattern regexp = Pattern.compile(("" + sValue).toLowerCase());
            query.filter(sField + "_." + CURRENT_LANG.getValue(), regexp);
         }
      }



      for(String sField : mapFilterText.keySet()){
         Object sValue = "" + mapFilterText.get(sField).getValue();

         if(sValue == null || "".equals(sValue)){
         }
         else{
            Pattern regexp = Pattern.compile("" + sValue, Pattern.CASE_INSENSITIVE);
            query.filter(sField, regexp);
         }
      }



      for(String sField : mapFilterBooleanTrueOnly.keySet()){
         boolean bChecked = mapFilterBooleanTrueOnly.get(sField).booleanValue();

         if(bChecked){
            try{
               String[] arrstrField = sField.split("\\.");
               query.field(arrstrField[0]).hasThisOne(Integer.parseInt(arrstrField[1]));
            }
            catch (Exception e){
               query.filter(sField, true);
            }
         }
      }



      //Date
      for(String sField : mapFilterDateFrom.keySet()){
         try{
            DateField df = mapFilterDateFrom.get(sField);

            long lDate = ((Date) df.getValue()).getTime();

            query.filter(sField + " >", lDate);
         }
         catch (Exception e){
         }
      }
      for(String sField : mapFilterDateTo.keySet()){
         try{
            DateField df = mapFilterDateTo.get(sField);

            long lDate = ((Date) df.getValue()).getTime();

            query.filter(sField + " <", lDate);
         }
         catch (Exception e){
         }
      }




      
      long iRecordsAmount = query.countAll();

      this.iMaxPages = (int) iRecordsAmount / PAGE_SIZE;
      if(iRecordsAmount % PAGE_SIZE == 0){
      }
      else{
         this.iMaxPages++;
      }

      if(iCurrentPage - 1 > iMaxPages){
         iCurrentPage = iMaxPages;
      }

      adjustNavigation();      
      
      

      //LET'S LOAD!
      LogTableFormatter ltf = new LogTableFormatter(1, true);
      
      try {
         for(Object obj : query.offset((iCurrentPage - 1)* PAGE_SIZE).limit(PAGE_SIZE).asList()){
            long lStartTimeRecord = System.currentTimeMillis();
            
            insertEmptyRecord(obj);
            
            if(log.isDebugEnabled()) {
               ltf.addCell(((MAbstractDataElement) obj).humanReadable(InterfaceConstants.LANGS.valueOf("" + CURRENT_LANG.getValue())));
               ltf.addCell((System.currentTimeMillis() - lStartTimeRecord) + " ms");
               ltf.br();
            }
         }
      }
      finally {
         if(log.isDebugEnabled()){
            log.trace(LOG + "\n" + ltf.toString());
         }
      }
      

      //Let's hightlight the things
      for(Object ID : table.getItemIds()){
         if(setSelectedIDes.contains((int) ID)){
            table.select(ID);            
         }
      }
      

      log.info(LOG + "ok, time=" + (System.currentTimeMillis() - lStartTime) + " ms");
      
      return iRecordOrder;
   }











   @SuppressWarnings({ "rawtypes", "unchecked" })
   public int insertEmptyRecord(Object obj){
      List<Object> row = new ArrayList<Object>();

      int ID = 0;

      for(CustomField cstField : descriptor.listFields){
         log.trace(LOG + "field=" + cstField.db);
         
         java.lang.reflect.Field field = getField(cstField.db);

         Object objValue;
         try{
            objValue = field.get(obj);
         }
         catch (Exception e){
            throw new Error("Field access value=" + cstField.db + " failed.", e);
         }

         if("ID".equalsIgnoreCase(cstField.db)){
            ID = (Integer) objValue;

            if(("" + objValue).equals(sItemId)){
               bRecordHasBeenFound = true;
            }

            if(bRecordHasBeenFound){
            }
            else{
               iRecordOrder++;
            }
         }



         //Related Boolean List
         if(field.isAnnotationPresent(AnnotationIncusiveList.class) ){

            CustomMultiCombo cmc = (CustomMultiCombo) cstField;
            
            
            Set<Integer> set = (Set<Integer>) objValue;
            Class classDescriptor = field.getAnnotation(AnnotationIncusiveList.class).foreign();
            
            
            switch(cmc.type){
               case COMBO:{
                  //Text version, just text
                  
                  List<String> listValues = new ArrayList();

                  for(Object objDescriptor : Caching.getList(classDescriptor)){
                     MAbstractDescriptor mAbstractDesriptor = (MAbstractDescriptor) objDescriptor;

                     if(set.contains(mAbstractDesriptor.ID)){
                        listValues.add(mAbstractDesriptor.name.get(InterfaceConstants.LANGS
                                          .valueOf("" + CURRENT_LANG.getValue())));
                     }
                  }

                  row.add(listValues);                  
                  
//                  StringBuilder sbCommaSeparatedStringValue = new StringBuilder();
//                  
//                  for(Object objDescriptor :  Caching.getList(classDescriptor)){
//                     MAbstractDescriptor mAbstractDesriptor = (MAbstractDescriptor) objDescriptor;
//                     
//                     if(set.contains(mAbstractDesriptor.ID)) {
//                        if(sbCommaSeparatedStringValue.length() > 0){
//                           sbCommaSeparatedStringValue.append(",");
//                        }
//                        
//                        sbCommaSeparatedStringValue.append(mAbstractDesriptor.name.get(InterfaceConstants.LANGS.valueOf("" + CURRENT_LANG.getValue())));
//                     }
//                  }
//                  
//                  row.add(sbCommaSeparatedStringValue.toString());
                  break;
               }
               default:{
                  //Table with rows

                  for(Object objDescriptor :  Caching.getList(classDescriptor)){
                     MAbstractDescriptor mAbstractDesriptor = (MAbstractDescriptor) objDescriptor;
                     row.add(set.contains(mAbstractDesriptor.ID));
                  }
                  break;
               }
            }
         }
         else if(field.isAnnotationPresent(AnnotationIncusiveListManual.class)){
            CustomFixedComboField ccf = (CustomFixedComboField) cstField;

            Set<Integer> set = (Set<Integer>) objValue;

            for(CustomFixedComboField.Element element : ccf.getElements()){
               row.add(set.contains(element.id));
            }
         }


         // MultiString
         else if(field.isAnnotationPresent(AnnotationMultiLangString.class) ){
            Map<InterfaceConstants.LANGS, String> map;
            try{
               map = (Map<InterfaceConstants.LANGS, String>) field.get(obj);
            }
            catch (Exception e){
               throw new Error("Field access value=" + cstField.db + " failed.", e);
            }

            String sValue =
                     map.get(InterfaceConstants.LANGS.valueOf("" + CURRENT_LANG.getValue()));

            if(sValue == null){
               sValue = "";
            }

            row.add(sValue);
         }

         
         
         
         
         //Combo
         else if(cstField instanceof CustomFixedComboField){
            // TODO

            CustomFixedComboField cdf = (CustomFixedComboField) cstField;


            if(field.isAnnotationPresent(AnnotationRelated.class) ){
               Class classForeign =
                        field.getAnnotation(AnnotationRelated.class).foreign();

               localizeCombos(cdf, classForeign);
            }

            try{
               Integer id = (Integer) objValue;

               if(cdf.type == CustomFixedComboField.TYPE.TEXT){
                  row.add((cdf.get(id)).text);
               }
               else if(cdf.type == CustomFixedComboField.TYPE.IMAGE){
                  row.add((cdf.get(id)).text);
               }
            }
            catch (NullPointerException e){
               row.add(null);
            }
         }

         
         //Combo
         else if(cstField instanceof CustomDatabaseComboField){
            // TODO

            CustomDatabaseComboField cdf = (CustomDatabaseComboField) cstField;


            if(field.isAnnotationPresent(AnnotationRelated.class) ){
               Class classForeign =
                        field.getAnnotation(AnnotationRelated.class).foreign();

               localizeCombos(cdf, classForeign);
            }
            else{
               throw new Error("No annotation 'related' for field=" + cstField.db);
            }

            try{
               Integer id = (Integer) objValue;

               if(cdf.type == CustomFixedComboField.TYPE.TEXT){
                  row.add((cdf.get(id)).text);
               }
               else if(cdf.type == CustomFixedComboField.TYPE.IMAGE){
                  row.add((cdf.get(id)).text);
               }
            }
            catch (NullPointerException e){
               row.add(null);
            }
         }
         

         
         
         
         
         // Date
         else if(field.isAnnotationPresent(AnnotationDate.class) ){
            row.add(new Date((Long) objValue));
         }
         
         
         
         

         // Time
         else if(field.isAnnotationPresent(AnnotationTime.class)){
            if(objValue == null){
               row.add("");
            }
            else{
               int iMunutes = (Integer) objValue;
   
               String sHours   = "" + iMunutes / 60;
               if(sHours.length() < 2) {
                  sHours = "0" + sHours;
               }
   
               String sMinutes = "" + iMunutes % 60;
               if(sMinutes.length() < 2) {
                  sMinutes = "0" + sMinutes;
               }
   
               row.add(sHours + ":" + sMinutes);
            }
         }

         //Price
         else if(field.isAnnotationPresent(AnnotationPrice.class) ){
            row.add(formatPrice(objValue));
         }

         //Image
         else if(field.isAnnotationPresent(AnnotationImage.class) ){
            CustomImageField cdf = (CustomImageField) cstField;

            if(cdf.isImageInTable){
               row.add(super.image2ClickableLabel("" + objValue, cdf.style.height));
            }
            else{
               row.add(objValue);
            }
         }
         


         // Default
         else{
            if(objValue == null){
               row.add("");
            }
            else {
               row.add(objValue);
            }
         }
      }
      
      //Let's check controllers
      for(CustomField cstField : descriptor.listFields){
         if(cstField instanceof FCustomController){
            //Controllers
         }
      }

      table.addItem(row.toArray(), ID);

      return ID;
   }









   public Object addNewRecordToDB(){
      MAbstractEditableDataElement abstractDataElement;
      try{
         abstractDataElement = (MAbstractEditableDataElement) classDB.newInstance();
      }
      catch (Exception e){
         throw new Error("Can not instance=" + classDB.getName(), e);
      }

      abstractDataElement.ID = MongoService.getUniqueID(classDB);

      //Filling empty names
//      if(abstractDataElement instanceof MAbstractDescriptor){
//         MAbstractDescriptor mAbstractDescriptor = (MAbstractDescriptor) abstractDataElement;
//         
//         String sValue = descriptor.mapDBFields.get("name").name + " " + abstractDataElement.ID;  
//         
//         for(InterfaceConstants.LANGS lang : InterfaceConstants.LANGS.values()) {
//            mAbstractDescriptor.name.put(lang, sValue);
//         }
//      }
      

      //Let's set constraints
      injectConstraints(abstractDataElement);

      MongoService.save(abstractDataElement);
      
      for(IHookAdd hookAdds : listHookAdds) {
         hookAdds.signal(this, abstractDataElement.ID);
      }

      return abstractDataElement;
   }




   public void deleteRecord(int ID){
      MAbstractEditableDataElement obj = (MAbstractEditableDataElement) MongoService.get(classDB, ID);

      obj.deleted = true;

      MongoService.save(obj);

      for(IHookDelete hookDelete : listHookDeletes) {
         hookDelete.signal(this, ID);
      }
   }



   
   
   public void undeleteRecord(int ID){
      MongoService.undelete(classDB, (int) itemId);
      
      
      for(IHookUndelete hookUnDelete : listHookUnDeletes) {
         hookUnDelete.signal(this, ID);
      }
   }
   
   
   





   private class LLangChange implements Property.ValueChangeListener{
      private static final long serialVersionUID = -1849407624556332799L;
      @Override
      public void valueChange(ValueChangeEvent event){
         application.lang = (InterfaceConstants.LANGS) CURRENT_LANG.getValue();

         reloadTableAndSelectRow(itemId);
      }
   }





   private class LTableNavigation implements Property.ValueChangeListener{
      private static final long serialVersionUID = 4070736652882106189L;

      @Override
      public void valueChange(ValueChangeEvent event){
         if(isEditMode){
         }
         else{
            try{
               itemId = Integer.parseInt("" +  event.getProperty());
               sItemId = new String("" + itemId);
            }
            catch (Throwable e){
               itemId = null;
               sItemId = null;
            }

            for(AbstractExtendedPanel panel : listExtraPanels){
               panel.changeFocus();
            }

            validateButtons();
         }
      }
   }










   private class LTable implements ItemClickEvent.ItemClickListener{
      private static final long serialVersionUID = -4185572626317638052L;

      public void itemClick(ItemClickEvent event){
         if(setMode.contains(AccessConstants.EditMode.CHANGE)){
            if(event.isDoubleClick()){

               if(isEditMode){
                  // if(finishEditMode() == false){
                  // return;
                  // }

                  if(saveChanges()){
                     table.setSelectable(true);
                     switchToReadMode();
                  }
                  else{
                     table.setSelectable(false);
                     table.select(itemId);
                     return;
                  }
               }
               else{
                  switchToEditMode();
               }
            }
            else{
               if(isEditMode){

                  if(saveChanges()){
                     table.setSelectable(true);
                     switchToReadMode();
                  }
                  else{
                     table.setSelectable(false);
                     table.select(itemId);
                     return;
                  }

                  // if(finishEditMode() == false){
                  // return;
                  // }

                  // int iCurrentPage = ComponentDBList.this.iCurrentPage;

                  // selectRow(itemId, false);

                  // if(iCurrentPage == ComponentDBList.this.iCurrentPage){
                  // table.unselect(itemId);
                  // table.select(event.getItemId());
                  // }
               }
            }
         }

         itemId = event.getItemId();
         sItemId = new String("" + event.getItemId());

         System.out.println("ID=" + sItemId);

         // if(bWritable){
         // btAction.setEnabled(true);
         // btDelete.setEnabled(true);
         // }
      }
   }

   protected class LHeader implements Table.HeaderClickListener{
      private static final long serialVersionUID = -757717169061143653L;





      public void headerClick(HeaderClickEvent event){
         String sColumn = (String) event.getPropertyId();

         CustomField cstmField = descriptor.mapNames.get(sColumn);

         if(cstmField.isSortable){
            // Remove old icons
            for(String sHeader : table.getColumnHeaders()){
               table.setColumnIcon(sHeader, null);
            }

            if(order.name.equals(sColumn)){
               if(order.type == Order.LESS){
                  order = new Order(Order.CREATER, cstmField.db, cstmField.name);
                  table.setColumnIcon(sColumn, new ThemeResource("../custom/asc1.png"));
               }
               else{
                  order = new Order(Order.LESS, cstmField.db, cstmField.name);
                  table.setColumnIcon(sColumn, new ThemeResource("../custom/dsc1.png"));
               }
            }
            else{
               order = new Order(Order.CREATER, cstmField.db, cstmField.name);
               table.setColumnIcon(sColumn, new ThemeResource("../custom/asc1.png"));
            }

            reloadTableAndSelectRow(itemId);
         }
      }
   }





   private void validateButtons(){
      if(cbShowDeleted.booleanValue()){
         btReload.setVisible(false);
         btAdd.setVisible(false);
         btEdit.setVisible(false);
         btDelete.setVisible(false);
         btSave.setVisible(false);
         btCancel.setVisible(false);
         
         btUnDelete.setVisible(true);
         panelBottomAddons.setVisible(false);
      }
      else{
         btUnDelete.setVisible(false);
         panelBottomAddons.setVisible(true);
         
         if(itemId == null || setBlockedRecords.contains(itemId)){
            btReload.setVisible(true);
            btAdd.setVisible(true);
            btEdit.setEnabled(false);
            btDelete.setEnabled(false);
            btSave.setVisible(false);
            btCancel.setVisible(false);
         }
         else{
            if(isEditMode){
               btReload.setVisible(false);
               btAdd.setVisible(false);
               btEdit.setEnabled(false);
               btEdit.setVisible(false);
               btDelete.setEnabled(false);
               btDelete.setVisible(false);
               btSave.setVisible(true);
               btCancel.setVisible(true);
            }
            else {
               btReload.setVisible(true);
               btAdd.setVisible(true);
               btEdit.setEnabled(true);
               btEdit.setVisible(true);
               btDelete.setEnabled(true);
               btDelete.setVisible(true);
               btSave.setVisible(false);
               btCancel.setVisible(false);
            }
         }
      }
   }





   private void switchToEditMode(){
      Iterator<Component> it = panelBottomAddons.getComponentIterator();
      while(it.hasNext()){
         it.next().setVisible(false);
      }
      
      
      try{
         oldValueMongoObject =
            (MAbstractEditableDataElement) MongoService.ds.find(classDB)
                                                          .filter(descriptor.listFields.get(0).db, Integer.parseInt("" + itemId)).get();
      }
      catch (Throwable e){
         //Something wrong with current row
         //let's discard edit
         return;
      }


      for(CustomField cstField : descriptor.listFields){
         if(cstField instanceof CustomFixedComboField){
            CustomFixedComboField cdf = (CustomFixedComboField) cstField;

            if(cdf.type == CustomFixedComboField.TYPE.IMAGE){
               try{
                  table.setColumnCollapsed(cstField.name + " ", true);
                  table.setColumnCollapsed(cstField.name, false);
               }
               catch (Throwable e){
               }
            }
         }

         try{
            mapOldValuesInTable.put(cstField.name, table.getItem(itemId).getItemProperty(cstField.name).getValue());
         }
         catch (Throwable e){
            //nothing to save, a new object
         }
      }


      isEditMode = true;
      table.setEditable(true);

      CURRENT_LANG.setEnabled(false);
      validateButtons();
      application.menubar.setEnabled(false);
   }







   public void switchToReadMode(){
      //Remove all editable components
      mapEditModeComponents.clear();
      
      Iterator<Component> it = panelBottomAddons.getComponentIterator();
      while(it.hasNext()){
         it.next().setVisible(true);
      }
      

      //Hide aux columns
      for(CustomField cstField : descriptor.listFields){
         if(cstField instanceof CustomFixedComboField){
            CustomFixedComboField cdf = (CustomFixedComboField) cstField;

            if(cdf.type == CustomFixedComboField.TYPE.IMAGE){
               try{
                  table.setColumnCollapsed(cstField.name + " ", false);
                  table.setColumnCollapsed(cstField.name, true);
               }
               catch (Throwable e){
               }
            }
         }
      }



      isEditMode = false;

      //table.setEditable(false);
      table.setTableFieldFactory(factory);
      table.setEditable(true);

      CURRENT_LANG.setEnabled(true);
      validateButtons();
      application.menubar.setEnabled(true);
   }




   public void cancelChanges(){
      for(CustomField cstField : descriptor.listFields){
         try{
            table.getItem(itemId).getItemProperty(cstField.name).setValue(mapOldValuesInTable.get(cstField.name));
         }
         catch (Throwable e){
            //something wrong wtih null value
            //let's skip it
         }
      }
   }





   @SuppressWarnings({ "unchecked", "rawtypes" })
   public boolean saveChanges(){

      if(oldValueMongoObject == null){
         // it is nothing to edit
         // Strange, but let's skip it
      }
      else{
         for(CustomField cstField : descriptor.listFields){
            try{
               if(cstField.isEditable){
                  java.lang.reflect.Field field = getField(cstField.db);
   
   
                  //Inclusive list
                  if(field.isAnnotationPresent(AnnotationIncusiveList.class)){
                     
                     Set<Integer> set;
                     try{
                        set = (Set<Integer>) field.get(oldValueMongoObject);
                     }
                     catch (Exception e){
                        throw new Error("Field access value=" + cstField.db + " failed.", e);
                     }
   
                     Class classDescriptor = field.getAnnotation(AnnotationIncusiveList.class).foreign();
                     
   
                     
                     CustomMultiCombo cdf = (CustomMultiCombo) cstField;
                     switch (cdf.type){
                        case TABLE:{
                           for(MAbstractDescriptor mAbstractDesriptor :
                              (List<MAbstractDescriptor>) MongoService.getList(classDescriptor)){
   
                              String sFieldName = mAbstractDesriptor.name.get(InterfaceConstants.LANGS.RU);
                              Boolean bValure =  Boolean.parseBoolean("" + table.getItem(itemId).getItemProperty(sFieldName));
   
                              if(bValure){
                                 set.add(mAbstractDesriptor.ID);
                              }
                              else {
                                 set.remove(mAbstractDesriptor.ID);
                              }
                           }
                           
                           break;                           
                        }
                        
                        
                        default:{
                           set.clear();
                           
                           Object objValue = table.getItem(itemId).getItemProperty(cstField.name);
                           String sAllInLine = "" + objValue;
   
                           Set<String> setValues = new HashSet();
                           
                           try{
                              String[] arrstrValues =
                                       sAllInLine.substring(1, sAllInLine.length() - 1).split(",");
   
                              for(String sValue : arrstrValues){
                                 setValues.add(sValue.trim());
                              }
                           }
                           catch (Exception e){
                           }                        
                           
                           for(MAbstractDescriptor mAbstractDesriptor :
                              (List<MAbstractDescriptor>) MongoService.getList(classDescriptor)){
                                 
                              if(setValues.contains(mAbstractDesriptor.name.get(InterfaceConstants.LANGS.valueOf("" + CURRENT_LANG.getValue())))){
                                 set.add(mAbstractDesriptor.ID);
                              }
                           }
                           
                           break;
                        }
                     }
                     
                     continue;
                  }
                  //Inclusive list Manual
                  else if(field.isAnnotationPresent(AnnotationIncusiveListManual.class) ){
                     Set<Integer> set;
                     try{
                        set = (Set<Integer>) field.get(oldValueMongoObject);
                     }
                     catch (Exception e){
                        throw new Error("Field access value=" + cstField.db + " failed.", e);
                     }
   
   
                     CustomFixedComboField ccf = (CustomFixedComboField) cstField;
   
   
                     for(CustomFixedComboField.Element element : ccf.getElements()){
                        String sFieldName = element.text;
                        Boolean bValure =  Boolean.parseBoolean("" + table.getItem(itemId).getItemProperty(sFieldName));
   
                        if(bValure){
                           set.add(element.id);
                        }
                        else {
                           set.remove(element.id);
                        }
                     }
                  }
                  else{
                     String sField = field.toString();
                     Object objValue = table.getItem(itemId).getItemProperty(cstField.name);
                     String sValue = "" + objValue;
   
                     // Let's validate the things
                     // 1. Empty line
                     if(cstField.isMust && ("".equals(sValue) || "null".equals(sValue))){
                        this.getApplication()
                                 .getMainWindow()
                                 .showNotification("Поле '" + cstField.name + "' не может быть пустым",
                                          Notification.TYPE_WARNING_MESSAGE);
   
                        return false;
                     }
   
                     Object objReady = null;
   
                     // MultiString
                     if(field.isAnnotationPresent(AnnotationMultiLangString.class) ){
                        Map<InterfaceConstants.LANGS, String> map;
                        try{
                           map = (Map<InterfaceConstants.LANGS, String>) field.get(oldValueMongoObject);
                        }
                        catch (Exception e){
                           throw new Error("Field access value=" + cstField.db + " failed.", e);
                        }
   
                        map.put(InterfaceConstants.LANGS.valueOf("" + CURRENT_LANG.getValue()), sValue);
                        
                        
                        //Let's copy the thing to the empty language values
                        if(sValue == null || "".equals(sValue)){
                        }
                        else{
                           for(InterfaceConstants.LANGS lang : InterfaceConstants.LANGS.values()){
                              String sLocalizedValue = map.get(lang); 
                              if(sLocalizedValue == null || "".endsWith(sLocalizedValue)) {
                                 map.put(lang, sValue);
                              }
                           }
                        }
   
                        objReady = map;
                     }
   
                     
                     // Combo
                     else if(cstField instanceof CustomFixedComboField){
                        // TODO
   
                        try{
                           CustomFixedComboField cdf = (CustomFixedComboField) cstField;
   
                           if(cdf.type == CustomFixedComboField.TYPE.TEXT){
                              objReady = cdf.get(sValue).id;
                           }
                           else if(cdf.type == CustomFixedComboField.TYPE.IMAGE){
                              objReady = cdf.get(sValue).id;
                           }
                        }
                        catch (Throwable e){
                           //Empty value
                           //it's ok
                           continue;
                        }
                     }
                     
                     
                     // Combo
                     else if(cstField instanceof CustomDatabaseComboField){
                        // TODO
   
                        try{
                           CustomDatabaseComboField cdf = (CustomDatabaseComboField) cstField;
   
                           if(cdf.type == CustomFixedComboField.TYPE.TEXT){
                              objReady = cdf.get(sValue).id;
                           }
                           else if(cdf.type == CustomFixedComboField.TYPE.IMAGE){
                              objReady = cdf.get(sValue).id;
                           }
                        }
                        catch (Throwable e){
                           //Empty value
                           //it's ok
                           continue;
                        }
                     }
                     
   
   
                     // Date
                     else if(field.isAnnotationPresent(AnnotationDate.class) ){
                        SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy", Locale.ENGLISH);
                        try{
                           objReady = (sdf.parse("" + objValue)).getTime();
                        }
                        catch (Throwable e){
                           this.getApplication()
                               .getMainWindow()
                               .showNotification("Ошибочный формат даты в '" + cstField.name + "'",
                                                 Notification.TYPE_WARNING_MESSAGE
                                                );
                           return false;
                        }
   
                     }
   
   
                     // Time
                     else if(field.isAnnotationPresent(AnnotationTime.class) ){
                        // 2. Time format
   
                        CustomDateField cdf = (CustomDateField) cstField;
                        
                        if("".equals("" + objValue)){
                           objReady = null;
                        }
                        else{    
                           try{
                              String sTime = "" + objValue;
                              String[] arrstrTime = sTime.split(":");
      
                              int iHours   = Integer.parseInt(arrstrTime[0]);
                              int iMinutes = Integer.parseInt(arrstrTime[1]);
      
                              if(iHours < 0 || iHours > 23 || iMinutes < 0 || iMinutes > 59){
                                 throw new Exception();
                              }
      
                              objReady = iHours * 60 + iMinutes;
                           }
                           catch (Exception e){
                              this.getApplication()
                                       .getMainWindow()
                                       .showNotification(
                                                "Поле '" + cstField.name + "' долнжо иметь формат " + cdf.format,
                                                Notification.TYPE_WARNING_MESSAGE);
      
                              return false;
                           }
                        }
                     }
   
                     //Price
                     else if(field.isAnnotationPresent(AnnotationPrice.class) ){
                        try{
                           String sPrice = "" + objValue;
                           int iPrice = (int) (Float.parseFloat(sPrice) * 100);
   
                           table.getItem(itemId).getItemProperty(cstField.name).setValue(new Float(iPrice) / 100);
   
                           objReady = iPrice;
                        }
                        catch (Throwable e){
                           this.getApplication()
                           .getMainWindow()
                           .showNotification(
                                             "Поле '" + cstField.name + "' долнжо иметь формат XXXXX.YY",
                                             Notification.TYPE_WARNING_MESSAGE
                                            );
   
                           return false;
                        }
                     }
   
   
                     //Image
                     else if(field.isAnnotationPresent(AnnotationImage.class)){
                        //We do not save images
                        continue;
                     }
                     else if(sField.contains("bool") || sField.contains("Boolean")){
                        objReady = Boolean.parseBoolean(sValue);
                     }
                     else if(sField.contains("float") || sField.contains("Float")){
                        objReady = Float.parseFloat(sValue);
                     }
                     else if(sField.contains("double") || sField.contains("Double")){
                        objReady = Double.parseDouble(sValue);
                     }
                     else if(sField.contains("int") || sField.contains("Integer")){
                        if(sValue == null || "".equals(sValue)){
                           objReady = null;
                        }
                        else{
                           objReady = Integer.parseInt(sValue);
                        }
                     }
   
                     // Default
                     else{
                        objReady = sValue;
                     }

                     field.set(oldValueMongoObject, objReady);
                  }
               }
            }
            catch (Throwable e){
               e.printStackTrace();
               this.getApplication().getMainWindow().showNotification(
                     "Ошибка сохранения поля " + cstField.name + " " + e.toString(), Notification.TYPE_WARNING_MESSAGE
                  );
               
               return false;
            }
         }



         //Inject constraints
         injectConstraints(oldValueMongoObject);



         try{
            MongoService.save((MAbstractEditableDataElement) oldValueMongoObject);
         }
         catch (MongoException.DuplicateKey e){
            String sMessage = e.getMessage();
            
            
            String[] arrstrName = sMessage.split("\\$");
            String sFieldName = arrstrName[1];
            arrstrName = sFieldName.split("_");
            sFieldName = arrstrName[0];

            this.getApplication()
                .getMainWindow()
                .showNotification("Поле '" + descriptor.mapDBFields.get(sFieldName).name + " должно быть уникальным",
                                   Notification.TYPE_WARNING_MESSAGE);
            
//            String[] arrstrValue = sMessage.split("\\\"");
//            System.out.println(arrstrValue[1]);
            
            return false;
         }
         catch (Throwable e){
            this.getApplication()
                .getMainWindow()
                .showNotification("Ошибка сохранения объекта " + e.toString(),
                                  Notification.TYPE_WARNING_MESSAGE);
            return false;
         }


         for(CustomField cstField : descriptor.listFields){
            String sOldValue = "" + mapOldValuesInTable.get(cstField.name);
            String sNewValue = "" + table.getItem(itemId).getItemProperty(cstField.name);

            if(sOldValue.equals(sNewValue)){
               //ok, no changes
            }
            else{
               MLog mLog = new MLog();
               mLog.ID = MongoService.getUniqueID(MLog.class);
               mLog.created = System.currentTimeMillis();
               mLog.relatedClass = oldValueMongoObject.getClass().getName();
               mLog.object = ((MAbstractDataElement) oldValueMongoObject).humanReadable(InterfaceConstants.LANGS.valueOf("" + CURRENT_LANG.getValue()));
               mLog.OID = (Integer) itemId;
               mLog.name = cstField.name;
               mLog.UID = application.UID;
               mLog.screen = MENU_TITLE;
               mLog.language = "" + CURRENT_LANG.getValue();
               mLog.old_value = sOldValue;
               mLog.new_value = sNewValue;

               MongoService.ds.save(mLog);
            }
         }
      }

      oldValueMongoObject = null;

      
      for(IHookEdit hookEdit : listHookEdits) {
         hookEdit.signal(this, (int) itemId);
      }
      

      return true;
   }





   private void reloadTableAndSelectRow(Object itemId){
      int iSelectedRecordOffset = reload();
      table.focus();

      if(itemId == null){
      }
      else{
         table.setCurrentPageFirstItemIndex(iSelectedRecordOffset);
         table.select(iSelectedRecordOffset);
      }
   }








   public class LChangeFilter implements ValueChangeListener{
      private static final long serialVersionUID = -7259535457067468749L;

      public void valueChange(com.vaadin.data.Property.ValueChangeEvent event){
         reloadTableAndSelectRow(itemId);
      }
   }


   
   
   
   
   
   
   
   
   
   
   
   
   private synchronized void adjustNavigation(){
      if(iCurrentPage <= 1 && iMaxPages <= 1){
         btFirst.setEnabled(false);
         btPrev.setEnabled(false);
         btNext.setEnabled(false);
         btLast.setEnabled(false);
         tfPage.setEnabled(false);
         btGo.setEnabled(false);

         iCurrentPage = 1;
      }
      else{
         if(iCurrentPage < 1){
            iCurrentPage = 1;
         }

         if(iCurrentPage == 1){
            btFirst.setEnabled(false);
            btPrev.setEnabled(false);
         }

         if(iCurrentPage >= iMaxPages){
            iCurrentPage = iMaxPages;

            btNext.setEnabled(false);
            btLast.setEnabled(false);
         }

         if(iCurrentPage < iMaxPages){
            btNext.setEnabled(true);
            btLast.setEnabled(true);
         }

         if(iCurrentPage > 1){
            btFirst.setEnabled(true);
            btPrev.setEnabled(true);
         }

         if(iCurrentPage == 1 && iMaxPages == 1){
            tfPage.setEnabled(false);
            btGo.setEnabled(false);
         }
         else{
            tfPage.setEnabled(true);
            btGo.setEnabled(true);
         }
      }

      tfPage.setValue(iCurrentPage);
      tfTotal.setValue("" + iMaxPages);
   }
   
   

   
   
   
   
   
   
   
   
   
   
   public class LLast implements ClickListener{
      private static final long serialVersionUID = -4360041638220736169L;

      @Override
      public void buttonClick(ClickEvent event){
         iCurrentPage = iMaxPages;

         reload();
      }
   }





   public class LNext implements ClickListener{
      private static final long serialVersionUID = 8808988354910728693L;

      @Override
      public void buttonClick(ClickEvent event){
         if(iCurrentPage - 1 < iMaxPages){
            iCurrentPage++;
         }
         reload();
      }
   }





   public class LChangePage implements ClickListener{
      private static final long serialVersionUID = -6604226086764024492L;

      @Override
      public void buttonClick(ClickEvent event){
         try{
            iCurrentPage = Integer.parseInt("" + tfPage.getValue());
         }
         catch (Throwable e){
            tfPage.setValue("" + iCurrentPage);
         }

         reload();
      }
   }





   public class LPrev implements ClickListener{
      private static final long serialVersionUID = -5452898555808735284L;

      @Override
      public void buttonClick(ClickEvent event){
         if(iCurrentPage > 1){
            iCurrentPage--;
         }
         reload();
      }
   }





   public class LFirst implements ClickListener{
      private static final long serialVersionUID = 2951488787976591188L;

      @Override
      public void buttonClick(ClickEvent event){
         iCurrentPage = 1;
         reload();
      }

   }

   
   
   /**
    * This class enables or disables groups of fields by controller value
    */
   public class LController implements ClickListener{
      private static final long serialVersionUID = -4316874685529219304L;
      
      private final FCustomController fController;
      
      public LController(FCustomController fController){
         this.fController = fController;
      }

      public void buttonClick(ClickEvent event){
         for(String sTableFieldName : fController.listFields){
            boolean bController = Boolean.parseBoolean("" + event.getButton().getValue());
            mapEditModeComponents.get(sTableFieldName).setEnabled(bController);
            
            if(bController){
            }
            else{
               mapEditModeComponents.get(sTableFieldName).setValue("");
            }
         }
      }
   }
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   

   public void addPanel(AbstractExtendedPanel panel, boolean bTop){
      listExtraPanels.add(panel);
      panel.setStyleName(Runo.PANEL_LIGHT);

      if(bTop){
         panelTopAddons.addComponent(sizeX(5));
         panelTopAddons.addComponent(panel);
      }
      else{
         panelBottomAddons.addComponent(sizeX(5));
         panelBottomAddons.addComponent(panel);
      }

   }
   
   
   public void hookDelete(IHookDelete hookDelete){
      listHookDeletes.add(hookDelete);
   }
   public void hookAdd(IHookAdd hookAdd){
      listHookAdds.add(hookAdd);
   }
   public void hookEdit(IHookEdit hookEdit){
      listHookEdits.add(hookEdit);
   }
   public void hookUndelete(IHookUndelete hookUndelete){
      listHookUnDeletes.add(hookUndelete);
   }






   private void injectConstraints(Object mongoObject){
      //Inject constraints
      for(Constraint.Criterion criterion : constraint.criteria){

         java.lang.reflect.Field field;
         try{
            field = classDB.getField(criterion.field);
            field.set(mongoObject, criterion.value);
         }
         catch (Exception e){
            this.getApplication()
            .getMainWindow()
            .showNotification("Ошибка сохранения внешней константы "
                              + criterion.field + " ->" +  criterion.value
                              + " " + e.toString(),
                              Notification.TYPE_ERROR_MESSAGE);
         }
      }
   }







   public void ahoyIveChangedSomething(){
      for(AbstractExtendedPanel panel : listExtraPanels){
         panel.changeFocus();
      }
   }

   
   
   public void grabSelectedIDes(){
      for(Object ID : table.getItemIds()){
         if(table.isSelected(ID)){
            setSelectedIDes.add((int) ID);
         }
         else{
            setSelectedIDes.remove((int) ID);
         }
      }
   }
}
