/*
 * FilesPane.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.views.files;

import com.google.gwt.core.client.JsArray;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.rstudio.core.client.cellview.ColumnSortInfo;
import org.rstudio.core.client.command.AppCommand;
import org.rstudio.core.client.files.FileSystemItem;
import org.rstudio.core.client.widget.OperationWithInput;
import org.rstudio.core.client.widget.ProgressOperationWithInput;
import org.rstudio.core.client.widget.Toolbar;
import org.rstudio.core.client.widget.ToolbarPopupMenu;
import org.rstudio.studio.client.common.FileDialogs;
import org.rstudio.studio.client.common.GlobalDisplay;
import org.rstudio.studio.client.common.filetypes.FileTypeRegistry;
import org.rstudio.studio.client.server.ServerDataSource;
import org.rstudio.studio.client.server.ServerError;
import org.rstudio.studio.client.server.ServerRequestCallback;
import org.rstudio.studio.client.workbench.commands.Commands;
import org.rstudio.studio.client.workbench.model.RemoteFileSystemContext;
import org.rstudio.studio.client.workbench.model.Session;
import org.rstudio.studio.client.workbench.model.SessionInfo;
import org.rstudio.studio.client.workbench.ui.WorkbenchPane;
import org.rstudio.studio.client.workbench.views.files.model.DirectoryListing;
import org.rstudio.studio.client.workbench.views.files.model.FileChange;
import org.rstudio.studio.client.workbench.views.files.model.PendingFileUpload;
import org.rstudio.studio.client.workbench.views.files.ui.*;

import java.util.ArrayList;

public class FilesPane extends WorkbenchPane implements Files.Display
{
   @Inject
   public FilesPane(GlobalDisplay globalDisplay,
                    FileDialogs fileDialogs,
                    Commands commands,
                    FileTypeRegistry fileTypeRegistry,
                    Session session,
                    Provider<FileCommandToolbar> pFileCommandToolbar)
   {
      super("Files");
      globalDisplay_ = globalDisplay ;
      commands_ = commands;
      fileDialogs_ = fileDialogs;
      fileTypeRegistry_ = fileTypeRegistry;
      pFileCommandToolbar_ = pFileCommandToolbar;
      session_ = session;
      ensureWidget();
   }
   
   public void setObserver(Files.Display.Observer observer)
   {
      observer_ = observer;
   }
   
   // implement forwarding (and null-safe) observer for sub-components
   private class DisplayObserverProxy implements Files.Display.Observer 
   {
      public void onFileSelectionChanged()
      {
         if (observer_ != null)
            observer_.onFileSelectionChanged();
         
      }
      public void onFileNavigation(FileSystemItem file)
      {
         if (observer_ != null)
            observer_.onFileNavigation(file);
      }
      
      public void onSelectAllValueChanged(boolean value)
      {
         if (observer_ != null)
            observer_.onSelectAllValueChanged(value);
      }
      
      public void onColumnSortOrderChanaged(
                                    JsArray<ColumnSortInfo> sortOrder)
      {
         if (observer_ != null)
            observer_.onColumnSortOrderChanaged(sortOrder);
      }
   }
   
   @Override
   public void setColumnSortOrder(JsArray<ColumnSortInfo> sortOrder)
   {
      filesList_.setColumnSortOrder(sortOrder);
   }
    
   public void listDirectory(final FileSystemItem directory, 
                             ServerDataSource<DirectoryListing> dataSource)
   {
      setProgress(true);
        
      dataSource.requestData(new ServerRequestCallback<DirectoryListing>(){
         public void onResponseReceived(DirectoryListing response)
         {
            setProgress(false);
            String lastBrowseable = null;
            if (!response.isParentBrowseable())
            {
               // if we can't go up, disable everything up to the current path
               lastBrowseable = directory.getPath();
            }
            else
            {
               // if we're in someone else's project, disable paths above
               // the project
               SessionInfo si = session_.getSessionInfo();
               if (si.getActiveProjectDir() != null && !si.isProjectOwner())
                  lastBrowseable = si.getActiveProjectDir().getPath();
            }
               
            filePathToolbar_.setPath(directory.getPath(), lastBrowseable);
            filesList_.displayFiles(directory, response.getFiles()); 
         }
         public void onError(ServerError error)
         {
            setProgress(false);
            globalDisplay_.showErrorMessage("File Listing Error",
                                            "Error navigating to " +
                                            directory.getPath() + ":\n\n" +
                                            error.getUserMessage());

            if (!directory.equalTo(FileSystemItem.home()))
            {
               observer_.onFileNavigation(FileSystemItem.home());
            }
         } 
      });
   }
   
   public void updateDirectoryListing(FileChange fileAction)
   {
      if (filesList_ != null) // can be called by file_changed event
                             // prior to widget creation
      {
         filesList_.updateWithAction(fileAction);
      }
   }
   
   public void renameFile(FileSystemItem from, FileSystemItem to)
   {
      filesList_.renameFile(from, to);
   }
    
   public void showFolderPicker(
         String caption,
         RemoteFileSystemContext fileSystemContext,
         FileSystemItem initialDir,
         ProgressOperationWithInput<FileSystemItem> operation)
   {
      fileDialogs_.chooseFolder(caption,
                                fileSystemContext,
                                initialDir,
                                operation);
   }
   
   public void showFileUpload(
                     String targetURL,
                     FileSystemItem targetDirectory, 
                     RemoteFileSystemContext fileSystemContext,
                     OperationWithInput<PendingFileUpload> completedOperation)
   {
      FileUploadDialog dlg = new FileUploadDialog(targetURL, 
                                                  targetDirectory,
                                                  fileDialogs_,
                                                  fileSystemContext,
                                                  completedOperation);
      dlg.showModal();
   } 
   
   public void selectAll()
   {
      filesList_.selectAll();
   }
   
   public void selectNone()
   {
      filesList_.selectNone();
   }
   
   public ArrayList<FileSystemItem> getSelectedFiles()
   {
      return filesList_.getSelectedFiles();
   } 
   
   @Override
   public void showHtmlFileChoice(FileSystemItem file, 
                                  Command onEdit,
                                  Command onBrowse)
   {
       final ToolbarPopupMenu menu = new ToolbarPopupMenu();
       
       String editLabel = AppCommand.formatMenuLabel(
          commands_.renameFile().getImageResource(), "Open in Editor", null);
       String openLabel = AppCommand.formatMenuLabel(
          commands_.openHtmlExternal().getImageResource(), 
          "View in Web Browser", 
          null);
       
       menu.addItem(new MenuItem(editLabel, true, onEdit));
       menu.addItem(new MenuItem(openLabel, true, onBrowse));
      
       menu.setPopupPositionAndShow(new PositionCallback() {
          @Override
          public void setPosition(int offsetWidth, int offsetHeight)
          {
             Event event = Event.getCurrentEvent();
             menu.setPopupPosition(event.getClientX(), event.getClientY());     
          }
       });
   }

   
   @Override 
   protected Widget createMainWidget()
   {
      filePathToolbar_ = new FilePathToolbar(new DisplayObserverProxy());

      // create file list and file progress
      filesList_ = new FilesList(new DisplayObserverProxy(), fileTypeRegistry_);

      DockLayoutPanel dockPanel = new DockLayoutPanel(Unit.PX);
      dockPanel.addNorth(filePathToolbar_, filePathToolbar_.getHeight());
      dockPanel.add(filesList_);
      // return container
      return dockPanel;
   }

   @Override
   public void onBeforeSelected()
   {
      if (needsInit)
      {
         needsInit = false;
         FileSystemItem home = FileSystemItem.home();
         observer_.onFileNavigation(home);
      }
   }

   @Override
   protected Toolbar createMainToolbar()
   {
      return pFileCommandToolbar_.get();
   }

   private boolean needsInit = false;
   private FilesList filesList_ ;
   private FilePathToolbar filePathToolbar_;
   private final GlobalDisplay globalDisplay_ ;
   private final FileDialogs fileDialogs_;
   private Files.Display.Observer observer_;
   private final Session session_;

   private final FileTypeRegistry fileTypeRegistry_;
   private final Commands commands_;
   private final Provider<FileCommandToolbar> pFileCommandToolbar_;
}
