/*
 * UnsavedChangesDialog.java
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */
package org.rstudio.studio.client.workbench.ui.unsaved;

import java.util.ArrayList;

import org.rstudio.core.client.SafeHtmlUtil;
import org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.widget.ModalDialog;
import org.rstudio.core.client.widget.Operation;
import org.rstudio.core.client.widget.OperationWithInput;
import org.rstudio.core.client.widget.ThemedButton;
import org.rstudio.studio.client.workbench.model.UnsavedChangesTarget;

import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.cell.client.ImageResourceCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.IdentityColumn;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.ProvidesKey;

public class UnsavedChangesDialog extends ModalDialog<UnsavedChangesDialog.Result>
{
   public class Result
   {
      public Result(ArrayList<UnsavedChangesTarget> saveTargets,
                    boolean alwaysSave)
      {
         saveTargets_ = saveTargets;
         alwaysSave_ = alwaysSave;
      }
      
      public ArrayList<UnsavedChangesTarget> getSaveTargets()
      {
         return saveTargets_;
      }
      
      public boolean getAlwaysSave()
      {
         return alwaysSave_;
      }
      
      private ArrayList<UnsavedChangesTarget> saveTargets_;
      private boolean alwaysSave_;
   }
   
   public UnsavedChangesDialog(
         String title,
         ArrayList<UnsavedChangesTarget> dirtyTargets,
         final OperationWithInput<Result> saveOperation,
         final Command onCancelled)
   {
      this(title, null, dirtyTargets, saveOperation, onCancelled);
   }
   
   public UnsavedChangesDialog(
         String title,
         String alwaysSaveOption,
         ArrayList<UnsavedChangesTarget> dirtyTargets,
         final OperationWithInput<Result> saveOperation,
         final Command onCancelled)
   {
      super(title, 
            saveOperation, 
            onCancelled != null ? new Operation() {
                                    @Override
                                    public void execute()
                                    {
                                       onCancelled.execute();
                                    }} :
                                  null);
      alwaysSaveOption_ = StringUtil.notNull(alwaysSaveOption);
      targets_ = dirtyTargets;
      
      setOkButtonCaption("Save Selected");
           	     
      addLeftButton(new ThemedButton("Don't Save", new ClickHandler() {
         @Override
         public void onClick(ClickEvent event)
         {
           closeDialog();
           saveOperation.execute(new Result(
                                       new ArrayList<UnsavedChangesTarget>(),
                                       false));
         } 
      }));    
   }

   @Override
   protected Widget createMainWidget()
   {
      // create cell table
      targetsCellTable_ = new CellTable<UnsavedChangesTarget>(
                                          15,
                                          UnsavedChangesCellTableResources.INSTANCE,
                                          KEY_PROVIDER);
      selectionModel_ = new MultiSelectionModel<UnsavedChangesTarget>(KEY_PROVIDER);
      targetsCellTable_.setSelectionModel(
         selectionModel_, 
         DefaultSelectionEventManager.<UnsavedChangesTarget> createCheckboxManager());
      targetsCellTable_.setWidth("100%", true);
      
      // add columns
      addSelectionColumn();
      addIconColumn();
      addNameAndPathColumn();
      
      // hook-up data provider 
      dataProvider_ = new ListDataProvider<UnsavedChangesTarget>();
      dataProvider_.setList(targets_);
      dataProvider_.addDataDisplay(targetsCellTable_);
      targetsCellTable_.setPageSize(targets_.size());
      
      // select all by default
      for (UnsavedChangesTarget editingTarget : dataProvider_.getList())
         selectionModel_.setSelected(editingTarget, true);
      
      // enclose cell table in scroll panel
      ScrollPanel scrollPanel = new ScrollPanel();
      scrollPanel.setStylePrimaryName(RESOURCES.styles().targetScrollPanel());
      scrollPanel.setWidget(targetsCellTable_);
      if (dataProvider_.getList().size() > 4)
         scrollPanel.setHeight("280px");
      
      // always save check box (may not be shown)
      chkAlwaysSave_ = new CheckBox(alwaysSaveOption_);
      
      // main widget
      VerticalPanel panel = new VerticalPanel();
      Label captionLabel = new Label(
                           "The following files have unsaved changes:");
      captionLabel.setStylePrimaryName(RESOURCES.styles().captionLabel());
      panel.add(captionLabel);
      panel.add(scrollPanel);      
      if (!StringUtil.isNullOrEmpty(alwaysSaveOption_))
      { 
         panel.add(chkAlwaysSave_);
         panel.setCellHeight(chkAlwaysSave_, "30px");
         panel.setCellVerticalAlignment(chkAlwaysSave_,
                                        HasVerticalAlignment.ALIGN_MIDDLE);

      }
      
      return panel;
   }
   
   private Column<UnsavedChangesTarget, Boolean> addSelectionColumn()
   {
      Column<UnsavedChangesTarget, Boolean> checkColumn = 
         new Column<UnsavedChangesTarget, Boolean>(new CheckboxCell(true, false)) 
         {
            @Override
            public Boolean getValue(UnsavedChangesTarget object)
            {
               return selectionModel_.isSelected(object);
            }   
         };
      checkColumn.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP);
      targetsCellTable_.addColumn(checkColumn); 
      targetsCellTable_.setColumnWidth(checkColumn, 25, Unit.PX);
      
      return checkColumn;
   }
  
   
   private Column<UnsavedChangesTarget, ImageResource> addIconColumn()
   {
      Column<UnsavedChangesTarget, ImageResource> iconColumn = 
         new Column<UnsavedChangesTarget, ImageResource>(new ImageResourceCell()) {

            @Override
            public ImageResource getValue(UnsavedChangesTarget object)
            {
               return object.getIcon();
            }
         };
      targetsCellTable_.addColumn(iconColumn);
      targetsCellTable_.setColumnWidth(iconColumn, 20, Unit.PX);
    
      return iconColumn;
   }
    
   private class NameAndPathCell extends AbstractCell<UnsavedChangesTarget>
   {

      @Override
      public void render(
            com.google.gwt.cell.client.Cell.Context context,
            UnsavedChangesTarget value, SafeHtmlBuilder sb)
      {
         if (value != null) 
         {
           Styles styles = RESOURCES.styles();
           
           String path = value.getPath();
           if (path != null)
           {
              SafeHtmlUtil.appendDiv(sb, styles.targetName(), value.getTitle());
              SafeHtmlUtil.appendDiv(sb, styles.targetPath(), path); 
           }
           else
           {
              SafeHtmlUtil.appendDiv(sb, 
                                     styles.targetUntitled(), 
                                     value.getTitle());
           }
         }
         
      }
      
   }
   
   private IdentityColumn<UnsavedChangesTarget> addNameAndPathColumn()
   {
      IdentityColumn<UnsavedChangesTarget> nameAndPathColumn = 
         new IdentityColumn<UnsavedChangesTarget>(new NameAndPathCell());
      
      targetsCellTable_.addColumn(nameAndPathColumn);
      targetsCellTable_.setColumnWidth(nameAndPathColumn, 350, Unit.PX);
      return nameAndPathColumn;
   }
   
   @Override
   protected Result collectInput()
   {
      return new Result(new ArrayList<UnsavedChangesTarget>(
                                          selectionModel_.getSelectedSet()),
                        chkAlwaysSave_.getValue());
   }

   @Override
   protected boolean validate(Result input)
   {
      return true;
   }
   
   static interface Styles extends CssResource
   {
      String targetScrollPanel();
      String captionLabel();
      String targetName();
      String targetPath();
      String targetUntitled();
   }

   static interface Resources extends ClientBundle
   {
      @Source("UnsavedChangesDialog.css")
      Styles styles();
   }

   static Resources RESOURCES = (Resources) GWT.create(Resources.class);

   public static void ensureStylesInjected()
   {
      RESOURCES.styles().ensureInjected();
   }
   
   private static final ProvidesKey<UnsavedChangesTarget> KEY_PROVIDER = 
      new ProvidesKey<UnsavedChangesTarget>() {
         @Override
         public Object getKey(UnsavedChangesTarget item)
         {
            return item.getId();
         }
    };
   
   private final ArrayList<UnsavedChangesTarget> targets_;
   
   private CellTable<UnsavedChangesTarget> targetsCellTable_; 
   private ListDataProvider<UnsavedChangesTarget> dataProvider_;
   private MultiSelectionModel<UnsavedChangesTarget> selectionModel_;
   
   private final String alwaysSaveOption_;
   private CheckBox chkAlwaysSave_;


}
