/*
 * Copyright (c) 2008-2011 Sonatype, Inc.
 * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
 *
 * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
 * Public License Version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License Version 3
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License Version 3 along with this program.  If not, see
 * http://www.gnu.org/licenses.
 *
 * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
 * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
 * All other trademarks are the property of their respective owners.
 */
Ext.form.RepositoryUrlDisplayField = Ext.extend(Ext.form.DisplayField, {
      setValue : function(repositories) {
        var links = '';

        for (var i = 0; i < repositories.length; i++)
        {
          if (i != 0)
          {
            links += ', ';
          }

          var path = 'index.html#view-repositories;' + repositories[i].repositoryId + '~browsestorage~' + repositories[i].path;
          if (repositories[i].canView)
          {
            links += '<a href="' + path + '">' + repositories[i].repositoryName + '</a>';
          }
          else
          {
            links += repositories[i].repositoryName;
          }
        }

        this.setRawValue(links);
        return this;
      }
    });

Ext.reg('repositoryUrlDisplayField', Ext.form.RepositoryUrlDisplayField);

Sonatype.repoServer.ArtifactInformationPanel = function(config) {
  var config = config || {};
  var defaultConfig = {};
  Ext.apply(this, config, defaultConfig);

  this.sp = Sonatype.lib.Permissions;

  this.deleteButton = new Ext.Button({
        xtype : 'button',
        text : 'Delete',
        handler : this.artifactDelete,
        scope : this
      });

  this.downloadButton = new Ext.Button({
        xtype : 'button',
        text : 'Download',
        handler : this.artifactDownload,
        scope : this
      });

  Sonatype.repoServer.ArtifactInformationPanel.superclass.constructor.call(this, {
        title : 'Artifact Information',
        autoScroll : true,
        border : true,
        frame : true,
        collapsible : false,
        collapsed : false,
        items : [{
              xtype : 'displayfield',
              fieldLabel : 'Repository Path',
              name : 'repositoryPath',
              anchor : Sonatype.view.FIELD_OFFSET_WITH_SCROLL,
              allowBlank : true,
              readOnly : true
            }, {
              xtype : 'displayfield',
              fieldLabel : 'Uploaded by',
              name : 'uploader',
              anchor : Sonatype.view.FIELD_OFFSET_WITH_SCROLL,
              allowBlank : true,
              readOnly : true
            }, {
              xtype : 'byteDisplayField',
              fieldLabel : 'Size',
              name : 'size',
              anchor : Sonatype.view.FIELD_OFFSET_WITH_SCROLL,
              allowBlank : true,
              readOnly : true
            }, {
              xtype : 'timestampDisplayField',
              fieldLabel : 'Uploaded Date',
              name : 'uploaded',
              anchor : Sonatype.view.FIELD_OFFSET_WITH_SCROLL,
              allowBlank : true,
              readOnly : true,
              formatter : function(value) {
                if (value)
                {
                  return new Date.parseDate(value, 'u').format('m.d.Y  h:m:s');
                }
              }
            }, {
              xtype : 'timestampDisplayField',
              fieldLabel : 'Last Modified',
              name : 'lastChanged',
              anchor : Sonatype.view.FIELD_OFFSET_WITH_SCROLL,
              allowBlank : true,
              readOnly : true,
              dateFormat : Ext.util.Format.dateRenderer('m/d/Y')
            }, {
              xtype : 'panel',
              layout : 'column',
              buttonAlign : 'left',
              items : [{}],
              buttons : [this.downloadButton, this.deleteButton]
            }, {
              xtype : 'fieldset',
              checkboxToggle : false,
              title : 'Checksums',
              anchor : Sonatype.view.FIELDSET_OFFSET,
              collapsible : false,
              autoHeight : true,
              layoutConfig : {
                labelSeparator : ''
              },
              items : [{
                    xtype : 'displayfield',
                    fieldLabel : 'SHA1',
                    name : 'sha1Hash',
                    anchor : Sonatype.view.FIELD_OFFSET_WITH_SCROLL,
                    allowBlank : true,
                    readOnly : true
                  }, {
                    xtype : 'displayfield',
                    fieldLabel : 'MD5',
                    name : 'md5Hash',
                    anchor : Sonatype.view.FIELD_OFFSET_WITH_SCROLL,
                    allowBlank : true,
                    readOnly : true
                  }]
            }, {
              xtype : 'fieldset',
              checkboxToggle : false,
              title : 'Contained In Repositories',
              anchor : Sonatype.view.FIELDSET_OFFSET,
              collapsible : false,
              autoHeight : true,
              layoutConfig : {
                labelSeparator : ''
              },
              items : [{
                    xtype : 'panel',
                    items : [{
                          xtype : 'repositoryUrlDisplayField',
                          name : 'repositories',
                          anchor : Sonatype.view.FIELD_OFFSET_WITH_SCROLL,
                          allowBlank : true,
                          readOnly : true
                        }]
                  }]
            }]
      });
};

Ext.extend(Sonatype.repoServer.ArtifactInformationPanel, Ext.form.FormPanel, {

      artifactDownload : function() {
        if (this.data)
        {
          Sonatype.utils.openWindow(this.data.resourceURI);
        }
      },

      artifactDelete : function() {
        if (this.data)
        {
          var url = this.data.resourceURI;

          Sonatype.MessageBox.show({
                title : 'Delete Repository Item?',
                msg : 'Delete the selected artifact ?',
                buttons : Sonatype.MessageBox.YESNO,
                scope : this,
                icon : Sonatype.MessageBox.QUESTION,
                fn : function(btnName) {
                  if (btnName == 'yes' || btnName == 'ok')
                  {
                    Ext.Ajax.request({
                          url : url,
                          callback : this.deleteRepoItemCallback,
                          scope : this,
                          method : 'DELETE'
                        });
                  }
                }
              });
        }
      },

      deleteRepoItemCallback : function(options, isSuccess, response) {
        if (isSuccess)
        {
          var panel = Sonatype.view.mainTabPanel.getActiveTab();
          var id = panel.getId();
          if (id == 'nexus-search')
          {
            panel.startSearch(panel, false);
          }
          else if (id == 'view-repositories')
          {
            panel.refreshHandler(null, null);
          }
        }
        else
        {
          Sonatype.MessageBox.alert('Error', response.status == 401 ? 'You don\'t have permission to delete artifacts in this repository' : 'The server did not delete the file/folder from the repository');
        }
      },

      setupNonLocalView : function(repositoryPath) {
        this.find('name', 'repositoryPath')[0].setRawValue(repositoryPath + ' (Not Locally Cached)');
        this.find('name', 'uploader')[0].setRawValue(null);
        this.find('name', 'size')[0].setRawValue(null);
        this.find('name', 'uploaded')[0].setRawValue(null);
        this.find('name', 'lastChanged')[0].setRawValue(null);
        this.find('name', 'sha1Hash')[0].setRawValue(null);
        this.find('name', 'md5Hash')[0].setRawValue(null);
        this.find('name', 'repositories')[0].setRawValue(null);

        this.find('name', 'uploader')[0].hide();
        this.find('name', 'size')[0].hide();
        this.find('name', 'uploaded')[0].hide();
        this.find('name', 'lastChanged')[0].hide();
        this.deleteButton.hide();
        var fieldsets = this.findByType('fieldset');

        for (var i = 0; i < fieldsets.length; i++)
        {
          fieldsets[i].hide();
        }
      },

      clearNonLocalView : function(showDeleteButton) {
        this.find('name', 'uploader')[0].show();
        this.find('name', 'size')[0].show();
        this.find('name', 'uploaded')[0].show();
        this.find('name', 'lastChanged')[0].show();
        if (showDeleteButton)
        {
          this.deleteButton.show();
        }
        var fieldsets = this.findByType('fieldset');

        for (var i = 0; i < fieldsets.length; i++)
        {
          fieldsets[i].show();
        }
      },

      showArtifact : function(data, artifactContainer) {
        this.data = data;
        if (data == null)
        {
          this.find('name', 'repositoryPath')[0].setRawValue(null);
          this.find('name', 'uploader')[0].setRawValue(null);
          this.find('name', 'size')[0].setRawValue(null);
          this.find('name', 'uploaded')[0].setRawValue(null);
          this.find('name', 'lastChanged')[0].setRawValue(null);
          this.find('name', 'sha1Hash')[0].setRawValue(null);
          this.find('name', 'md5Hash')[0].setRawValue(null);
          this.find('name', 'repositories')[0].setRawValue(null);
        }
        else
        {
          Ext.Ajax.request({
                url : this.data.resourceURI + '?describe=info&isLocal=true',
                callback : function(options, isSuccess, response) {
                  if (isSuccess)
                  {
                    var infoResp = Ext.decode(response.responseText);

                    if (!infoResp.data.presentLocally)
                    {
                      this.setupNonLocalView(infoResp.data.repositoryPath);
                    }
                    else
                    {
                      this.clearNonLocalView(infoResp.data.canDelete);
                      this.form.setValues(infoResp.data);
                    }
                  }
                  else
                  {
                    if (response.status = 404)
                    {
                      artifactContainer.hideTab(this);
                    }
                    else
                    {
                      Sonatype.utils.connectionError(response, 'Unable to retrieve artifact information.');
                    }
                  }
                },
                scope : this,
                method : 'GET',
                suppressStatus : '404'
              });
        }
      }
    });

Sonatype.Events.addListener('fileContainerInit', function(items) {
      items.push(new Sonatype.repoServer.ArtifactInformationPanel({
            name : 'artifactInformationPanel',
            tabTitle : 'Artifact Information',
            preferredIndex : 20
          }));
    });

Sonatype.Events.addListener('fileContainerUpdate', function(artifactContainer, data) {
      var panel = artifactContainer.find('name', 'artifactInformationPanel')[0];

      if (data == null || !data.leaf)
      {
        panel.showArtifact(null, artifactContainer);
      }
      else
      {
        panel.showArtifact(data, artifactContainer);
      }
    });

Sonatype.Events.addListener('artifactContainerInit', function(items) {
      items.push(new Sonatype.repoServer.ArtifactInformationPanel({
            name : 'artifactInformationPanel',
            tabTitle : 'Artifact Information',
            preferredIndex : 20
          }));
    });

Sonatype.Events.addListener('artifactContainerUpdate', function(artifactContainer, payload) {
      var panel = artifactContainer.find('name', 'artifactInformationPanel')[0];

      if (payload == null || !payload.leaf)
      {
        panel.showArtifact(null, artifactContainer);
      }
      else
      {
        panel.showArtifact(payload, artifactContainer);
      }
    });
/*
 * Copyright (c) 2008-2011 Sonatype, Inc.
 * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
 *
 * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
 * Public License Version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License Version 3
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License Version 3 along with this program.  If not, see
 * http://www.gnu.org/licenses.
 *
 * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
 * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
 * All other trademarks are the property of their respective owners.
 */
// must pass in feedUrl that's local to our domain, 'cause we ain't got no proxy
// yet
// config: feedUrl required
Sonatype.SearchStore = function(config) {
  var config = config || {};
  var defaultConfig = {
    searchUrl : Sonatype.config.servicePath + '/lucene/search'
  };
  Ext.apply(this, config, defaultConfig);

  Sonatype.SearchStore.superclass.constructor.call(this, {
        proxy : new Ext.data.HttpProxy({
              url : this.searchUrl,
              method : 'GET'
            }),
        reader : new Ext.data.JsonReader({
              root : 'data',
              totalProperty : 'totalCount'
            }, Ext.data.Record.create([{
                  name : 'groupId'
                }, {
                  name : 'artifactId'
                }, {
                  name : 'version'
                }, {
                  name : 'highlightedFragment'
                }, {
                  name : 'artifactHits'
                }, {
                  name : 'latestRelease'
                }, {
                  name : 'latestReleaseRepositoryId'
                }, {
                  name : 'latestSnapshot'
                }, {
                  name : 'latestSnapshotRepositoryId'
                }])),
        listeners : {
          'beforeload' : {
            fn : function(store, options) {
              store.proxy.getConnection().on('requestcomplete', function(conn, response, options) {
                    if (response.responseText)
                    {
                      var statusResp = Ext.decode(response.responseText);
                      if (statusResp)
                      {
                        this.grid.totalRecords = statusResp.totalCount;
                        if (statusResp.tooManyResults)
                        {
                          this.grid.setWarningLabel('Too many results, please refine the search condition.');
                        }
                        else
                        {
                          this.grid.clearWarningLabel();
                        }
                      }
                    }
                  }, this, {
                    single : true
                  });
              return true;
            },
            scope : this
          },
          'load' : {
            fn : function(store, records, options) {
              this.grid.updateRowTotals(this.grid);
            },
            scope : this
          }
        }
      });
};

Ext.extend(Sonatype.SearchStore, Ext.data.Store, {});

Sonatype.repoServer.SearchResultGrid = function(config) {

  Ext.apply(this, config);

  this.sp = Sonatype.lib.Permissions;

  this.totalRecords = 0;

  this.defaultStore = new Sonatype.SearchStore({
        grid : this
      });

  this.store = this.defaultStore;

  this.defaultColumnModel = new Ext.grid.ColumnModel({
        columns : [{
              header : 'Group',
              dataIndex : 'groupId',
              sortable : true
            }, {
              header : 'Artifact',
              dataIndex : 'artifactId',
              sortable : true
            }, {
              header : 'Version',
              dataIndex : 'version',
              sortable : true,
              renderer : this.formatVersionLink
            }, {
              id : 'search-result-download',
              header : 'Download',
              sortable : true,
              renderer : this.formatDownloadLinks
            }]
      });

  this.colModel = this.defaultColumnModel;

  this.clearButton = new Ext.Button({
        text : 'Clear Results',
        icon : Sonatype.config.resourcePath + '/images/icons/clear.gif',
        cls : 'x-btn-text-icon',
        handler : this.clearResults,
        disabled : true,
        scope : this
      });

  this.fetchMoreBar = new Ext.Toolbar({
        ctCls : 'search-all-tbar',
        items : ['Displaying 0 records', {
              xtype : 'tbspacer'
            }, this.clearButton]
      });
  this.subtitleBar = new Ext.Toolbar({
        ctCls : 'search-all-tbar',
        items : [{
              xtype : 'panel',
              html : '<img src="images/pom_obj.gif" />'
            }, {
              xtype : 'label',
              text : 'Pom file'
            }, {
              xtype : 'tbspacer'
            }, {
              xtype : 'panel',
              html : '<img src="images/jar_obj.gif" />'
            }, {
              xtype : 'label',
              text : 'Jar artifact'
            }, {
              xtype : 'tbspacer'
            }, {
              xtype : 'panel',
              html : '<img src="images/jar_sources_obj.gif" />'
            }, {
              xtype : 'label',
              text : 'Sources artifact'
            }, {
              xtype : 'tbspacer'
            }, {
              xtype : 'panel',
              html : '<img src="images/jar_javadoc_obj.gif" />'
            }, {
              xtype : 'label',
              text : 'Javadoc artifact'
            }]
      });

  Sonatype.repoServer.SearchResultGrid.superclass.constructor.call(this, {
        region : 'center',
        id : 'search-result-grid',
        loadMask : {
          msg : 'Loading Results...'
        },
        stripeRows : true,
        sm : new Ext.grid.RowSelectionModel({
              singleSelect : true
            }),

        viewConfig : {
          forceFit : true
        },

        bbar : [this.fetchMoreBar/* , '->', this.subtitleBar */],

        listeners : {
          render : {
            fn : function(grid) {

              var store = grid.getStore();
              var view = grid.getView();
              grid.tip = new Ext.ToolTip({
                    target : view.mainBody,
                    delegate : '.x-grid3-row',
                    maxWidth : 500,
                    trackMouse : true,
                    renderTo : document.body,
                    listeners : {
                      beforeshow : function(tip) {
                        var rowIndex = view.findRowIndex(tip.triggerElement);
                        var record = store.getAt(rowIndex);

                        if (!record)
                        {
                          return false;
                        }

                        var highlightedFragment = record.get('highlightedFragment');

                        if (Ext.isEmpty(highlightedFragment))
                        {
                          return false;
                        }

                        tip.body.dom.innerHTML = highlightedFragment;
                      }
                    }
                  });
            },
            scope : this
          }
        }
      });
};

Ext.extend(Sonatype.repoServer.SearchResultGrid, Ext.grid.GridPanel, {
      formatVersionLink : function(value, p, record, rowIndex, colIndex, store) {
        if (!store.reader.jsonData.collapsed)
        {
          return record.get('version');
        }

        var latest = record.get('latestRelease');

        if (!latest)
        {
          latest = record.get('latestSnapshot');
        }

        return 'Latest: ' + latest + ' <a href="#nexus-search;gav~' + record.get('groupId') + '~' + record.get('artifactId')
            + '~~~~kw,versionexpand " onmousedown="cancel_bubble(event)" onclick="cancel_bubble(event); return true;">(Show All Versions)</a>';
      },
      formatDownloadLinks : function(value, p, record, rowIndex, colIndex, store) {
        var hitIndex = 0;
        if (store.reader.jsonData.collapsed)
        {
          var repoToUse = record.get('latestReleaseRepositoryId');

          if (!repoToUse)
          {
            repoToUse = record.get('latestSnapshotRepositoryId');
          }

          for (var i = 0; i < record.data.artifactHits.length; i++)
          {
            if (record.data.artifactHits[i].repositoryId == repoToUse)
            {
              hitIndex = i;
              break;
            }
          }
        }

        var icons = [];
        var links = [];

        for (var i = 0; i < record.data.artifactHits[hitIndex].artifactLinks.length; i++)
        {
          var cls = record.data.artifactHits[hitIndex].artifactLinks[i].classifier;
          var ext = record.data.artifactHits[hitIndex].artifactLinks[i].extension;
          var rep = record.data.artifactHits[hitIndex].repositoryId;
          var grp = record.data.groupId;
          var art = record.data.artifactId;
          var ver = record.data.version;

          if (store.reader.jsonData.collapsed)
          {
            ver = record.data.latestRelease;
            if (Ext.isEmpty(ver))
            {
              ver = record.data.latestSnapshot;
            }
          }

          var link = Sonatype.config.repos.urls.redirect + '?r=' + rep + '&g=' + grp + '&a=' + art + '&v=' + ver + '&e=' + ext;

          if (!Ext.isEmpty(cls))
          {
            link += '&c=' + cls;
          }

          var icon = null;
          // if (ext == 'pom' && !cls)
          // {
          // icon = "images/pom_obj.gif";
          // }
          // else if ((ext == '' || ext == 'jar') && !cls)
          // {
          // icon = "images/jar_obj.gif";
          // }
          // else if ((ext == '' || ext == 'jar') && cls == 'sources')
          // {
          // icon = "images/jar_sources_obj.gif";
          // }
          // else if ((ext == '' || ext == 'jar') && cls == 'javadoc')
          // {
          // icon = "images/jar_javadoc_obj.gif";
          // }

          var desc = (cls ? (cls + '.' + ext) : ext);

          if (icon)
          {
            desc = '<img src="' + icon + '" title=' + desc + ' />';
          }

          desc = '<a href="' + link + '" onmousedown="cancel_bubble(event)" onclick="cancel_bubble(event); return true;" target="_blank">'
              //
              + desc +
              //
              '</a>'

          if (icon)
          {
            icons.push(desc);
          }
          else
          {
            links.push(desc);
          }

        }

        var value = '';

        for (var i = 0; i < icons.length; i++)
        {
          if (i > 0)
          {
            value += ', ';
          }
          value += icons[i];
        }

        if (icons.length > 0)
        {
          value += '<BR>';
        }

        for (var i = 0; i < links.length; i++)
        {
          if (i > 0)
          {
            value += ', ';
          }
          value += links[i];
        }

        return value;
      },

      switchStore : function(grid, store, columnModel) {
        if (store == null)
        {
          store = grid.defaultStore;
        }

        if (columnModel == null)
        {
          columnModel = grid.defaultColumnModel;
        }

        if (store)
        {
          this.clearResults();
        }

        grid.reconfigure(store, columnModel);
      },
      toggleExtraInfo : function(rowIndex) {
        var rowEl = new Ext.Element(this.getView().getRow(rowIndex));
        var input = rowEl.child('.copy-pom-dep', true);
        input.select(); // @todo: why won't this field highlight?!!!!
        rowEl.toggleClass('x-grid3-row-expanded');
      },

      updateRowTotals : function(p) {
        var count = p.store.getCount();

        p.clearButton.setDisabled(count == 0);

        if (count == 0 || count > p.totalRecords)
        {
          p.totalRecords = count;
        }

        p.fetchMoreBar.items.items[0].destroy();
        p.fetchMoreBar.items.removeAt(0);
        p.fetchMoreBar.insertButton(0, new Ext.Toolbar.TextItem('Displaying Top ' + count + ' records'));
      },

      setWarningLabel : function(s) {
        this.searchPanel.setWarningLabel(s);
      },

      clearWarningLabel : function() {
        this.searchPanel.clearWarningLabel();
      },

      clearResults : function() {
        this.store.baseParams = {};
        this.store.removeAll();
        delete this.store.baseParams['dir'];
        delete this.store.baseParams['sort'];
        delete this.store.sortInfo;
        delete this.view.sortState;
        this.store.sortToggle = {};
        this.view.mainHd.select('td').removeClass(this.sortClasses);
        this.fireEvent('sortchange', this.grid, null);
        this.updateRowTotals(this);
        this.clearWarningLabel();
      }
    });

cancel_bubble = function(e) {
  if (!e)
    var e = window.event;
  e.cancelBubble = true;
  if (e.stopPropagation)
    e.stopPropagation();
}

/*
 * Copyright (c) 2008-2011 Sonatype, Inc.
 * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
 *
 * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
 * Public License Version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License Version 3
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License Version 3 along with this program.  If not, see
 * http://www.gnu.org/licenses.
 *
 * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
 * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
 * All other trademarks are the property of their respective owners.
 */
var REINDEX_ACTION = function ( rec, full ) {
  var indexUrl = null;
  if ( full ) {
    indexUrl = Sonatype.config.servicePath + '/data_index';
  } else {
    indexUrl = Sonatype.config.servicePath + '/data_incremental_index';
  }

  var url = indexUrl +
    rec.data.resourceURI.slice(Sonatype.config.host.length + Sonatype.config.servicePath.length);
  
  //make sure to provide /content path for repository root requests like ../repositories/central
  if (/.*\/repositories\/[^\/]*$/i.test(url) || /.*\/repo_groups\/[^\/]*$/i.test(url)){
    url += '/content';
  }
  
  Ext.Ajax.request({
    url: url,
    callback: function(options, isSuccess, response) {
      if ( !isSuccess ) {
        Sonatype.utils.connectionError( response, 'The server did not re-index the repository.' );
      }
    },
    scope: this,
    method: 'DELETE'
  });
}
  
Sonatype.Events.addListener( 'repositoryMenuInit',
  function( menu, repoRecord ) {
    if ( Sonatype.lib.Permissions.checkPermission( 'nexus:index', Sonatype.lib.Permissions.DELETE ) 
        && repoRecord.get( 'repoType' ) != 'virtual' ) {
      menu.add({
        text: 'Repair Index',
        handler: function( rec ) {
          REINDEX_ACTION( rec, true );
        },
        scope: this
      });
      menu.add( {
        text: 'Update Index',
        handler: function( rec ) {
          REINDEX_ACTION( rec, false );
        },
        scope: this
      });
    }
  }
);

Sonatype.Events.addListener( 'repositoryContentMenuInit',
  function( menu, repoRecord, contentRecord ) {
    if ( Sonatype.lib.Permissions.checkPermission( 'nexus:index', Sonatype.lib.Permissions.DELETE ) 
        && repoRecord.data['repoType'] != 'virtual' ) {
      menu.add( {
        text: 'Update Index',
        handler: function( rec ) {
          REINDEX_ACTION( rec, false );
        },
        scope: this
      });
    }
  }
);
/*
 * Copyright (c) 2008-2011 Sonatype, Inc.
 * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
 *
 * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
 * Public License Version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License Version 3
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License Version 3 along with this program.  If not, see
 * http://www.gnu.org/licenses.
 *
 * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
 * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
 * All other trademarks are the property of their respective owners.
 */
Sonatype.repoServer.IndexBrowserPanel = function(config) {
  var config = config || {};
  var defaultConfig = {
    url : '',
    showRepositoryDropDown : false
  };

  Ext.apply(this, config, defaultConfig);

  if (!this.root)
  {
    this.root = new Ext.tree.TreeNode({
          text : '(Not Available)',
          id : '/',
          singleClickExpand : true,
          expanded : true
        });
  }

  if (this.showRepositoryDropDown)
  {
    this.toolbarInitEvent = 'indexBrowserToolbarInit';
  }

  Sonatype.repoServer.IndexBrowserPanel.superclass.constructor.call(this, {
        nodeIconClass : 'x-tree-node-nexus-icon',
        useNodeIconClassParam : 'locallyAvailable',
        appendAttributeToId : 'type'
      });
};

Sonatype.Events.addListener('indexBrowserToolbarInit', function(treepanel, toolbar) {
      if (treepanel.showRepositoryDropDown)
      {
        var store = new Ext.data.SimpleStore({
              fields : ['id', 'name']
            });
        treepanel.repocombo = new Ext.form.ComboBox({
              width : 200,
              store : store,
              valueField : 'id',
              displayField : 'name',
              editable : false,
              mode : 'local',
              triggerAction : 'all',
              listeners : {
                select : {
                  fn : function(combo, record, index) {
                    for (var i = 0; i < treepanel.payload.data.hits.length; i++)
                    {
                      if (record.data.id == treepanel.payload.data.hits[i].repositoryId)
                      {
                        var repoDetails = treepanel.payload.data.getRepoDetails(record.data.id, treepanel.payload.data.repoList);
                        treepanel.updatePayload({
                              data : {
                                showCtx : treepanel.payload.data.showCtx,
                                id : repoDetails.repositoryId,
                                name : repoDetails.repositoryName,
                                resourceURI : repoDetails.repositoryURL,
                                format : repoDetails.repositoryContentClass,
                                repoType : repoDetails.repositoryKind,
                                hitIndex : treepanel.payload.data.hitIndex,
                                useHints : treepanel.payload.data.useHints,
                                expandPath : treepanel.payload.data.expandPath,
                                hits : treepanel.payload.data.hits,
                                rec : treepanel.payload.data.rec,
                                isSnapshot : repoDetails.repositoryPolicy == 'SNAPSHOT',
                                repoList : treepanel.payload.data.repoList,
                                getRepoDetails : treepanel.payload.data.getRepoDetails
                              }
                            }, true);
                      }
                    }
                  },
                  scope : treepanel
                }
              }
            });

        toolbar.push(' ', '-', ' ', 'Viewing Repository:', ' ', treepanel.repocombo);
      }
    });

Ext.extend(Sonatype.repoServer.IndexBrowserPanel, Sonatype.panels.TreePanel, {
      nodeExpandHandler : function() {
        var parentContainer = this.parentContainer;

        if (this.payload.data.expandPath)
        {
          this.selectPath(this.getDefaultPathFromPayload(), 'text', function(success, node) {
                if (success)
                {
                  if (node.ownerTree.nodeClickEvent)
                  {
                    Sonatype.Events.fireEvent(node.ownerTree.nodeClickEvent, node, node.ownerTree.nodeClickPassthru);
                  }
                }
                else if (parentContainer != null)
                {
                  parentContainer.loadComplete();
                }
              });
        }
      },
      getDefaultPathFromPayload : function() {
        var rec = this.payload.data.rec;
        var hitIndex = this.payload.data.hitIndex;

        var basePath = '/' + this.payload.data.name + '/' + rec.data.groupId.replace(/\./g, '/') + '/' + rec.data.artifactId + '/' + rec.data.version + '/' + rec.data.artifactId + '-' + rec.data.version;

        for (var i = 0; i < rec.data.artifactHits[hitIndex].artifactLinks.length; i++)
        {
          var link = rec.data.artifactHits[hitIndex].artifactLinks[i];

          if (Ext.isEmpty(link.classifier))
          {
            if (link.extension != 'pom')
            {
              return basePath + '.' + link.extension;
            }
          }
        }

        var link = rec.data.artifactHits[hitIndex].artifactLinks[0];
        return basePath + (link.classifier ? ('-' + link.classifier) : '') + '.' + link.extension;
      },
      refreshHandler : function(button, e) {
        Sonatype.Events.fireEvent(this.nodeClickEvent, null, this.nodeClickPassthru);
        if (this.root)
        {
          this.root.destroy();
        }
        if (this.payload)
        {
          this.loader.url = this.payload.data.resourceURI + '/index_content';

          if (this.payload.data.useHints)
          {
            this.loader.baseParams = {
              groupIdHint : this.payload.data.rec.data.groupId,
              artifactIdHint : this.payload.data.rec.data.artifactId
            }
          }
          else
          {
            this.loader.baseParams = null;
          }

          this.setRootNode(new Ext.tree.AsyncTreeNode({
                text : this.payload.data[this.titleColumn],
                leaf : false,
                path : '/',
                singleClickExpand : true,
                expanded : true,
                listeners : {
                  expand : {
                    fn : this.nodeExpandHandler,
                    scope : this
                  }
                }
              }));
        }
        else
        {
          this.setRootNode(new Ext.tree.TreeNode({
                text : '(Not Available)',
                id : '/',
                singleClickExpand : true,
                expanded : true
              }));
        }

        if (this.innerCt)
        {
          this.innerCt.update('');
          this.afterRender();
        }
      },

      updatePayload : function(payload, onlyPayload) {
        this.oldPayload = this.payload;
        this.payload = payload;

        if (!onlyPayload && this.repocombo)
        {
          var store = this.repocombo.store;
          store.removeAll();
          if (this.payload)
          {
            for (var i = 0; i < this.payload.data.hits.length; i++)
            {
              var repoDetails = this.payload.data.getRepoDetails(this.payload.data.hits[i].repositoryId, this.payload.data.repoList);
              if ((this.payload.data.isSnapshot && repoDetails.repositoryPolicy == 'SNAPSHOT') || (!this.payload.data.isSnapshot && repoDetails.repositoryPolicy == 'RELEASE'))
              {
                var record = new Ext.data.Record.create({
                      name : 'id'
                    }, {
                      name : 'name'
                    });

                store.add(new record({
                      id : repoDetails.repositoryId,
                      name : repoDetails.repositoryName
                    }));
              }
            }

            this.repocombo.setValue(this.payload.data.id);
          }
        }

        this.refreshHandler();
      }
    });
/*
 * Copyright (c) 2008-2011 Sonatype, Inc.
 * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
 *
 * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
 * Public License Version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License Version 3
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License Version 3 along with this program.  If not, see
 * http://www.gnu.org/licenses.
 *
 * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
 * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
 * All other trademarks are the property of their respective owners.
 */
Sonatype.repoServer.SearchPanel = function(config) {
  var config = config || {};
  var defaultConfig = {};
  Ext.apply(this, config, defaultConfig);

  this.grid = new Sonatype.repoServer.SearchResultGrid({
        searchPanel : this
      });

  this.searchTypes = [];

  // fire event for plugins to add their own search items
  Sonatype.Events.fireEvent('searchTypeInit', this.searchTypes, this);

  // no items, no page
  if (this.searchTypes.length < 1)
  {
    return;
  }

  var defaultSearchTypeIndex = 0;
  // find default
  for (var i = 0; i < this.searchTypes.length; i++)
  {
    if (this.searchTypes[i].defaultQuickSearch)
    {
      defaultSearchTypeIndex = i;
      break;
    }
  }

  this.searchTypeButton = new Ext.Button({
        text : this.searchTypes[defaultSearchTypeIndex].text,
        value : this.searchTypes[defaultSearchTypeIndex].value,
        tooltip : 'Click for more search options',
        handler : this.switchSearchType,
        scope : this,
        menu : {
          items : this.searchTypes
        }
      });

  this.searchToolbar = new Ext.Toolbar({
        ctCls : 'search-all-tbar',
        items : [this.searchTypeButton, this.convertToFieldObject(this.searchTypes[defaultSearchTypeIndex].panelItems[0])]
      });

  this.repoBrowserContainer = new Sonatype.repoServer.RepositoryIndexBrowserContainer({
        region : 'south',
        split : true,
        height : 375,
        showRepositoryDropDown : true
      });

  Sonatype.repoServer.SearchPanel.superclass.constructor.call(this, {
        layout : 'border',
        hideMode : 'offsets',
        tbar : this.searchToolbar,
        items : [this.grid, this.repoBrowserContainer]
      });

  // this.grid.getSelectionModel().on('rowselect',
  // this.displayArtifactInformation, this);
  this.grid.on('rowclick', this.rowClickHandler, this);
  this.grid.on('keypress', this.keypressHandler, this);
  this.grid.clearButton.on('click', this.clearArtifactInformation, this);
  this.repoBrowserContainer.repositoryBrowser.getSelectionModel().on('selectionchange', this.focusGrid, this);

  this.lastbookmark = '';
  this.searchTask = new Ext.util.DelayedTask(this.delayedDisplayArtifactInformation, this, []);
};

Ext.extend(Sonatype.repoServer.SearchPanel, Ext.Panel, {
      focusGrid : function() {
        // this.grid.doLayout();
        // this.grid.focus(false, 10);
      },

      clearArtifactInformation : function(button, e) {
        this.repoBrowserContainer.updatePayload(null);
      },

      rowClickHandler : function(grid, rowindex, evt) {
        this.displayArtifactInformation(grid.getSelectionModel(), rowindex, grid.getSelectionModel().getSelected());
      },

      keypressHandler : function(evt) {
        this.searchTask.cancel();
        if (evt.keyCode == 13)
        {
          this.delayedDisplayArtifactInformation();
        }
        else
        {
          this.searchTask.delay(2000);
        }
      },

      delayedDisplayArtifactInformation : function() {
        this.displayArtifactInformation(this.grid.getSelectionModel(), -1, this.grid.getSelectionModel().getSelected());
      },

      displayArtifactInformation : function(selectionModel, index, rec) {
        var searchType = this.getSearchType(this.searchTypeButton.value);
        if (typeof searchType.showArtifactContainer != 'function' || searchType.showArtifactContainer(rec))
        {
          var hitIndex = 0;
          if (rec.store.reader.jsonData.collapsed)
          {
            var repoToUse = rec.get('latestReleaseRepositoryId');

            if (!repoToUse)
            {
              repoToUse = rec.get('latestSnapshotRepositoryId');
            }

            for (var i = 0; i < rec.data.artifactHits.length; i++)
            {
              if (rec.data.artifactHits[i].repositoryId == repoToUse)
              {
                hitIndex = i;
                break;
              }
            }
          }

          var getRepoDetails = function(repoId, repoList) {
            for (var i = 0; i < repoList.length; i++)
            {
              if (repoList[i].repositoryId == repoId)
              {
                return repoList[i];
              }
            }

            return null;
          };

          var repoDetails = getRepoDetails(rec.data.artifactHits[hitIndex].repositoryId, rec.store.reader.jsonData.repoDetails);

          var payload = {
            data : {
              showCtx : true,
              id : repoDetails.repositoryId,
              name : repoDetails.repositoryName,
              resourceURI : repoDetails.repositoryURL,
              format : repoDetails.repositoryContentClass,
              repoType : repoDetails.repositoryKind,
              hitIndex : hitIndex,
              useHints : true,
              expandPath : true,
              hits : rec.data.artifactHits,
              rec : rec,
              isSnapshot : repoDetails.repositoryPolicy == 'SNAPSHOT',
              repoList : rec.store.reader.jsonData.repoDetails,
              getRepoDetails : getRepoDetails
            }
          };

          this.repoBrowserContainer.updatePayload(payload);
        }
      },
      // search type switched on the drop down button
      switchSearchType : function(button, event) {
        // if event is null, this is called directly, and we
        // we will reset regardless if already selected, otherwise
        // no need to do anything if already set to same value
        if (event == null || this.searchTypeButton.value != button.value)
        {
          this.searchTypeButton.value = button.value;
          this.searchTypeButton.setText(this.getSearchType(button.value).text);
          this.clearWarningLabel();
          this.loadSearchPanel();
          this.switchStore();
        }
      },
      // load the dynamic panel
      loadSearchPanel : function() {
        // first remove current items
        while (this.searchToolbar.items.length > 1)
        {
          var item = this.searchToolbar.items.last();
          this.searchToolbar.items.remove(item);
          item.destroy();
        }

        // now add the other items
        var searchType = this.getSearchType(this.searchTypeButton.value);

        if (searchType != null)
        {
          for (var i = 0; i < searchType.panelItems.length; i++)
          {
            // can't simply add object config to toolbar, need to create
            // a real item
            this.searchToolbar.add(this.convertToFieldObject(searchType.panelItems[i]));
          }
        }
      },
      // toolbar only supports adding certain types of items, so we
      // need to do some special handling
      convertToFieldObject : function(config) {
        if (config.xtype == 'nexussearchfield')
        {
          return new Ext.app.SearchField(config);
        }
        else if (config.xtype == 'textfield')
        {
          return new Ext.form.TextField(config);
        }
        else
        {
          return config;
        }
      },
      // different search types may have different stores
      switchStore : function() {
        var searchType = this.getSearchType(this.searchTypeButton.value);
        this.grid.switchStore(this.grid, searchType.store, searchType.columnModel);
      },
      // retrieve the specified search type object
      getSearchType : function(value) {
        for (var i = 0; i < this.searchTypes.length; i++)
        {
          if (this.searchTypes[i].value == value)
          {
            return this.searchTypes[i];
          }
        }

        return null;
      },
      // set the warning in the toolbar
      setWarningLabel : function(s) {
        this.clearWarningLabel();
        this.warningLabel = this.searchToolbar.addText('<span class="x-toolbar-warning">' + s + '</span>');
      },
      // clear the warning in the toolbar
      clearWarningLabel : function() {
        if (this.warningLabel)
        {
          this.warningLabel.destroy();
          this.warningLabel = null;
        }
      },
      // start the search
      startSearch : function(panel, updateHistory) {
        if (updateHistory)
        {
          // update history in address bar of browser
          panel.extraData = null;
          Sonatype.utils.updateHistory(panel);
        }

        var searchType = this.getSearchType(this.searchTypeButton.value);

        if (panel.grid.store.sortInfo)
        {
          panel.grid.store.sortInfo = null;
          panel.grid.getView().updateHeaders();
        }

        searchType.searchHandler.call(this, panel);
      },
      // get the records from the server using grid
      fetchRecords : function(panel, reverse) {
        panel.repoBrowserContainer.updatePayload(null);
        panel.grid.totalRecords = 0;
        panel.grid.store.removeAll();
        panel.grid.store.load();

        panel.grid.doSort = reverse;
        panel.grid.store.on('load', this.sortResults, panel);
      },
      sortResults : function(store, records, options) {
        if (this.grid.doSort)
        {
          this.grid.doSort = null;
          store.sort('version', 'desc');
        }

        if (records.length > 0)
        {
          this.grid.getSelectionModel().selectFirstRow();
          this.displayArtifactInformation(this.grid.getSelectionModel(), 0, this.grid.getSelectionModel().getSelected());
        }
      },
      // start the quick search, we will look at all search types
      // and try to guess which type of search to use
      startQuickSearch : function(v) {
        var defaultSearchType = null;
        var searchType = null;
        for (var i = 0; i < this.searchTypes.length; i++)
        {
          // this default search will be used if no other searches match
          if (this.searchTypes[i].defaultQuickSearch == true)
          {
            defaultSearchType = this.searchTypes[i];
          }
          else if (this.searchTypes[i].quickSearchCheckHandler.call(this, this, v))
          {
            searchType = this.searchTypes[i];
            break;
          }
        }

        // apply the default search
        if (searchType == null && defaultSearchType != null)
        {
          searchType = defaultSearchType;
        }

        if (searchType != null)
        {
          this.switchSearchType({
                value : searchType.value
              }, null);

          searchType.quickSearchHandler.call(this, this, v);
          this.startSearch(this, true);
        }
      },
      // apply the bookmark params to page
      applyBookmark : function(bookmark) {
        if (bookmark)
        {
          if (this.lastbookmark == bookmark)
          {
            return;
          }

          this.lastbookmark = bookmark;

          var parts = decodeURIComponent(bookmark).split('~');

          // if type not specified, simply do a quick search and guess
          if (parts.length == 1)
          {
            this.startQuickSearch(bookmark);
          }
          else if (parts.length > 1)
          {
            this.switchSearchType({
                  value : parts[0]
                }, null);

            var searchType = this.getSearchType(parts[0]);

            searchType.applyBookmarkHandler.call(this, this, parts);
          }
        }
      },
      // get the params to build bookmark
      getBookmark : function() {
        var searchType = this.getSearchType(this.searchTypeButton.value);

        var bookmark = searchType.getBookmarkHandler.call(this, this);

        if (this.extraData)
        {
          var extras = this.extraData.split(',');

          if (extras.length > 0)
          {
            bookmark += '~';
            for (var i = 0; i < extras.length; i++)
            {
              if (i > 0)
              {
                bookmark += ',';
              }
              bookmark += extras[i];
            }
          }
        }

        this.lastbookmark = bookmark;

        return bookmark;
      }
    });

// Add the quick search
Sonatype.Events.addListener('searchTypeInit', function(searchTypes, panel) {
      // keyword is the default, we always want first in list
      searchTypes.splice(0, 0, {
            value : 'quick',
            text : 'Keyword Search',
            scope : panel,
            handler : panel.switchSearchType,
            defaultQuickSearch : true,
            // use the default store
            store : null,
            quickSearchCheckHandler : function(panel, value) {
              return true;
            },
            quickSearchHandler : function(panel, value) {
              panel.getTopToolbar().items.itemAt(1).setRawValue(value);
            },
            searchHandler : function(panel) {
              var value = panel.getTopToolbar().items.itemAt(1).getRawValue();

              if (value)
              {
                panel.grid.store.baseParams = {};
                panel.grid.store.baseParams['q'] = value;
                panel.grid.store.baseParams['collapseresults'] = true;
                panel.fetchRecords(panel);
              }
            },
            applyBookmarkHandler : function(panel, data) {
              panel.extraData = null;
              panel.getTopToolbar().items.itemAt(1).setRawValue(data[1]);
              panel.startSearch(panel, false);
            },
            getBookmarkHandler : function(panel) {
              var result = panel.searchTypeButton.value;
              result += '~';
              result += panel.getTopToolbar().items.itemAt(1).getRawValue();
              return result;
            },
            panelItems : [{
                  xtype : 'nexussearchfield',
                  name : 'single-search-field',
                  searchPanel : panel,
                  width : 300
                }]
          });
    });

// Add the classname search
Sonatype.Events.addListener('searchTypeInit', function(searchTypes, panel) {
      searchTypes.push({
            value : 'classname',
            text : 'Classname Search',
            scope : panel,
            // use the default store
            store : null,
            handler : panel.switchSearchType,
            quickSearchCheckHandler : function(panel, value) {
              return value.search(/^[a-z.]*[A-Z]/) == 0;
            },
            quickSearchHandler : function(panel, value) {
              panel.getTopToolbar().items.itemAt(1).setRawValue(value);
            },
            searchHandler : function(panel) {
              var value = panel.getTopToolbar().items.itemAt(1).getRawValue();

              if (value)
              {
                panel.grid.store.baseParams = {};
                panel.grid.store.baseParams['cn'] = value;
                panel.fetchRecords(panel);
              }
            },
            applyBookmarkHandler : function(panel, data) {
              panel.getTopToolbar().items.itemAt(1).setRawValue(data[1]);
              panel.startSearch(panel, false);
            },
            getBookmarkHandler : function(panel) {
              var result = panel.searchTypeButton.value;
              result += '~';
              result += panel.getTopToolbar().items.itemAt(1).getRawValue();

              return result;
            },
            panelItems : [{
                  xtype : 'nexussearchfield',
                  name : 'single-search-field',
                  searchPanel : panel,
                  width : 300
                }]
          });
    });

// Add the gav search
Sonatype.Events.addListener('searchTypeInit', function(searchTypes, panel) {
      var enterHandler = function(f, e) {
        if (e.getKey() == e.ENTER)
        {
          this.startSearch(this, true);
        }
      };

      var gavPopulator = function(panel, data) {
        panel.extraData = null;

        // groupId
        if (data.length > 1)
        {
          panel.getTopToolbar().items.itemAt(2).setRawValue(data[1]);
        }
        // artifactId
        if (data.length > 2)
        {
          panel.getTopToolbar().items.itemAt(5).setRawValue(data[2]);
        }
        // version
        if (data.length > 3)
        {
          panel.getTopToolbar().items.itemAt(8).setRawValue(data[3]);
        }
        // packaging
        if (data.length > 4)
        {
          panel.getTopToolbar().items.itemAt(11).setRawValue(data[4]);
        }
        // classifier
        if (data.length > 5)
        {
          panel.getTopToolbar().items.itemAt(14).setRawValue(data[5]);
        }
        // extra params, comma seperated list of params
        if (data.length > 6)
        {
          panel.extraData = data[6];
        }
      }

      searchTypes.push({
            value : 'gav',
            text : 'GAV Search',
            scope : panel,
            // use the default store
            store : null,
            handler : panel.switchSearchType,
            quickSearchCheckHandler : function(panel, value) {
              return value.indexOf(':') > -1;
            },
            quickSearchHandler : function(panel, value) {
              var parts = value.split(':');
              var data = ['gav'];
              for (var i = 0; i < parts.length; i++)
              {
                data.push(parts[i]);
              }
              gavPopulator(panel, data);
            },
            searchHandler : function(panel) {
              this.grid.store.baseParams = {};

              // groupId
              var v = panel.getTopToolbar().items.itemAt(2).getRawValue();
              if (v)
              {
                panel.grid.store.baseParams['g'] = v;
              }
              // artifactId
              v = panel.getTopToolbar().items.itemAt(5).getRawValue();
              if (v)
              {
                panel.grid.store.baseParams['a'] = v;
              }
              // version
              v = panel.getTopToolbar().items.itemAt(8).getRawValue();
              if (v)
              {
                panel.grid.store.baseParams['v'] = v;
              }
              // packaging
              v = panel.getTopToolbar().items.itemAt(11).getRawValue();
              if (v)
              {
                panel.grid.store.baseParams['p'] = v;
              }
              // classifier
              v = panel.getTopToolbar().items.itemAt(14).getRawValue();
              if (v)
              {
                panel.grid.store.baseParams['c'] = v;
              }

              panel.grid.store.baseParams['collapseresults'] = true;

              // go through the extras and process them.
              if (panel.extraData)
              {
                var extras = panel.extraData.split(',');

                for (var i = 0; i < extras.length; i++)
                {
                  if (extras[i] == 'versionexpand')
                  {
                    panel.grid.store.baseParams['versionexpand'] = true;
                  }
                }
              }

              if (panel.grid.store.baseParams['g'] == null && panel.grid.store.baseParams['a'] == null && panel.grid.store.baseParams['v'] == null)
              {
                panel.setWarningLabel('A group, an artifact or a version is required to run a search.');
                return;
              }

              panel.clearWarningLabel();

              panel.fetchRecords(panel, true);
            },
            applyBookmarkHandler : function(panel, data) {
              gavPopulator(panel, data);
              panel.startSearch(this, false);
            },
            getBookmarkHandler : function(panel) {
              var result = panel.searchTypeButton.value;
              // groupId
              result += '~';
              var v = panel.getTopToolbar().items.itemAt(2).getRawValue();
              if (v)
              {
                result += v;
              }
              // artifactId
              result += '~';
              v = panel.getTopToolbar().items.itemAt(5).getRawValue();
              if (v)
              {
                result += v;
              }
              // version
              result += '~';
              v = panel.getTopToolbar().items.itemAt(8).getRawValue();
              if (v)
              {
                result += v;
              }
              // packaging
              result += '~';
              v = panel.getTopToolbar().items.itemAt(11).getRawValue();
              if (v)
              {
                result += v;
              }
              // classifier
              result += '~';
              v = panel.getTopToolbar().items.itemAt(14).getRawValue();
              if (v)
              {
                result += v;
              }

              return result;
            },
            panelItems : ['Group:', {
                  xtype : 'textfield',
                  id : 'gavsearch-group',
                  size : 80,
                  listeners : {
                    'specialkey' : {
                      fn : enterHandler,
                      scope : panel
                    }
                  }
                }, {
                  xtype : 'tbspacer'
                }, 'Artifact:', {
                  xtype : 'textfield',
                  id : 'gavsearch-artifact',
                  size : 80,
                  listeners : {
                    'specialkey' : {
                      fn : enterHandler,
                      scope : panel
                    }
                  }
                }, {
                  xtype : 'tbspacer'
                }, 'Version:', {
                  xtype : 'textfield',
                  id : 'gavsearch-version',
                  size : 80,
                  listeners : {
                    'specialkey' : {
                      fn : enterHandler,
                      scope : panel
                    }
                  }
                }, {
                  xtype : 'tbspacer'
                }, 'Packaging:', {
                  xtype : 'textfield',
                  id : 'gavsearch-packaging',
                  size : 80,
                  listeners : {
                    'specialkey' : {
                      fn : enterHandler,
                      scope : panel
                    }
                  }
                }, {
                  xtype : 'tbspacer'
                }, 'Classifier:', {
                  xtype : 'textfield',
                  id : 'gavsearch-classifier',
                  size : 80,
                  listeners : {
                    'specialkey' : {
                      fn : enterHandler,
                      scope : panel
                    }
                  }
                }, {
                  xtype : 'tbspacer'
                }, {
                  icon : Sonatype.config.resourcePath + '/images/icons/search.gif',
                  cls : 'x-btn-icon',
                  scope : panel,
                  handler : function() {
                    this.startSearch(this, true);
                  }
                }]
          });
    });

// Add the checksum search
Sonatype.Events.addListener('searchTypeInit', function(searchTypes, panel) {
      if (Sonatype.lib.Permissions.checkPermission('nexus:identify', Sonatype.lib.Permissions.READ))
      {
        searchTypes.push({
              value : 'checksum',
              text : 'Checksum Search',
              scope : panel,
              // use the default store
              store : null,
              handler : panel.switchSearchType,
              quickSearchCheckHandler : function(panel, value) {
                return value.search(/^[0-9a-f]{40}$/) == 0;
              },
              quickSearchHandler : function(panel, value) {
                panel.getTopToolbar().items.itemAt(1).setRawValue(value);
              },
              searchHandler : function(panel) {
                var value = panel.getTopToolbar().items.itemAt(1).getRawValue();

                if (value)
                {
                  panel.grid.store.baseParams = {};
                  panel.grid.store.baseParams['sha1'] = value;
                  panel.fetchRecords(panel);
                }
              },
              applyBookmarkHandler : function(panel, data) {
                panel.getTopToolbar().items.itemAt(1).setRawValue(data[1]);
                panel.startSearch(panel, false);
              },
              getBookmarkHandler : function(panel) {
                var result = panel.searchTypeButton.value;
                result += '~';
                result += panel.getTopToolbar().items.itemAt(1).getRawValue();

                return result;
              },
              panelItems : [{
                    xtype : 'nexussearchfield',
                    name : 'single-search-field',
                    searchPanel : panel,
                    width : 300
                  }, {
                    xtype : 'button',
                    text : 'Browse...',
                    searchPanel : panel,
                    tooltip : 'Click to select a file. It will not be uploaded to the ' + 'remote server, an SHA1 checksum is calculated locally and sent to ' + 'Nexus to find a match. This feature requires Java applet ' + 'support in your web browser.',
                    handler : function(b) {
                      var filename = null;

                      if (!document.digestApplet)
                      {
                        b.searchPanel.grid.fetchMoreBar.addText('<div id="checksumContainer" style="width:10px">' + '<applet code="org/sonatype/nexus/applet/DigestApplet.class" ' + 'archive="' + Sonatype.config.resourcePath + '/digestapplet.jar" '
                            + 'width="1" height="1" name="digestApplet"></applet>' + '</div>');
                      }
                      else
                      {
                        filename = document.digestApplet.selectFile();
                      }

                      if (!filename)
                      {
                        var fileInput = b.detachInputFile();
                        filename = fileInput.getValue();
                      }

                      if (!filename)
                      {
                        return;
                      }

                      b.disable();

                      var setFilenameLabel = function(panel, s) {
                        if (panel.filenameLabel)
                        {
                          panel.filenameLabel.destroy();
                        }
                        panel.filenameLabel = s ? panel.searchToolbar.addText('<span style="color:#808080;">' + s + '</span>') : null;
                      };

                      setFilenameLabel(b.searchPanel, 'Calculating checksum...');

                      var f = function(b, filename) {
                        var sha1 = 'error calculating checksum';
                        if (document.digestApplet)
                        {
                          sha1 = document.digestApplet.digest(filename);
                        }

                        b.searchPanel.getTopToolbar().items.itemAt(1).setRawValue(sha1);
                        setFilenameLabel(b.searchPanel, filename);
                        b.enable();
                        b.searchPanel.startSearch(b.searchPanel, true);
                      }
                      f.defer(200, b, [b, filename]);
                    }
                  }]
            });
      }
    });

/*
 * Copyright (c) 2008-2011 Sonatype, Inc.
 * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
 *
 * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
 * Public License Version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License Version 3
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License Version 3 along with this program.  If not, see
 * http://www.gnu.org/licenses.
 *
 * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
 * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
 * All other trademarks are the property of their respective owners.
 */
// This container will host both the repository browser and the artifact
// information panel
Sonatype.repoServer.RepositoryIndexBrowserContainer = function(config) {
  var config = config || {};
  var defaultConfig = {
    showRepositoryDropDown : false
  };
  Ext.apply(this, config, defaultConfig);

  this.repositoryBrowser = new Sonatype.repoServer.IndexBrowserPanel({
        payload : this.payload,
        tabTitle : this.tabTitle,
        region : 'center',
        url : this.initialUrl,
        root : this.initialRoot,
        parentContainer : this,
        nodeClickEvent : 'indexNodeClickedEvent',
        nodeClickPassthru : {
          container : this
        },
        showRepositoryDropDown : this.showRepositoryDropDown
      });

  this.artifactContainer = new Sonatype.repoServer.ArtifactContainer({
        collapsible : true,
        collapsed : true,
        region : 'east',
        split : true,
        width : '600'

      });
  Sonatype.repoServer.RepositoryIndexBrowserContainer.superclass.constructor.call(this, {
        layout : 'border',
        // this hideMode causes the tab to properly render when coming back from
        // hidden
        hideMode : 'offsets',
        items : [this.repositoryBrowser, this.artifactContainer]
      });
};

Ext.extend(Sonatype.repoServer.RepositoryIndexBrowserContainer, Ext.Panel, {
      updatePayload : function(payload) {
        if (payload == null)
        {
          this.repositoryBrowser.updatePayload(null);
          this.artifactContainer.collapsePanel();
        }
        else
        {
          if (payload.data.expandPath)
          {
            if (!this.loadMask)
            {
              this.loadMask = new Ext.LoadMask(this.getEl(), {
                    msg : 'Loading search result...'
                  });
            }
            this.loadMask.show();
          }
          this.repositoryBrowser.updatePayload(payload);
        }
      },
      loadComplete : function() {
        if (this.loadMask)
        {
          this.loadMask.hide();
        }
      }
    });

// Add the browse storage and browse index panels to the repo
Sonatype.Events.addListener('repositoryViewInit', function(cardPanel, rec) {
      if (rec.data.resourceURI && rec.data.repoType != 'virtual' && rec.data.format == 'maven2')
      {
        var panel = new Sonatype.repoServer.RepositoryIndexBrowserContainer({
              name : 'browseindex',
              tabTitle : 'Browse Index',
              autoExpand : false,
              payload : rec,
              initialUrl : rec.data.resourceURI + '/index_content',
              initialRoot : new Ext.tree.AsyncTreeNode({
                    text : rec.data['name'],
                    path : '/',
                    singleClickExpand : true,
                    expanded : false
                  })
            });

        if (cardPanel.items.getCount() > 0)
        {
          cardPanel.insert(1, panel);
        }
        else
        {
          cardPanel.add(panel);
        }
      }
    });

Sonatype.Events.addListener('indexNodeClickedEvent', function(node, passthru) {
      if (passthru && passthru.container)
      {
        if (node && node.isLeaf())
        {
          if (!passthru.container.loadMask)
          {
            passthru.container.loadMask = new Ext.LoadMask(passthru.container.getEl(), {
                  msg : 'Loading search result...'
                });
          }
          passthru.container.loadMask.show();

          Ext.Ajax.request({
                scope : this,
                method : 'GET',
                options : {
                  dontForceLogout : true
                },
                cbPassThru : {
                  node : node,
                  container : passthru.container
                },
                callback : function(options, isSuccess, response) {
                  if (passthru.container.loadMask)
                  {
                    passthru.container.loadMask.hide();
                  }
                  if (isSuccess)
                  {
                    var json = Ext.decode(response.responseText);

                    var resourceURI = Sonatype.config.servicePath + '/repositories/' + options.cbPassThru.node.attributes.repositoryId + '/content' + json.data.repositoryPath;

                    options.cbPassThru.container.artifactContainer.updateArtifact({
                          leaf : true,
                          resourceURI : resourceURI,
                          groupId : options.cbPassThru.node.attributes.groupId,
                          artifactId : options.cbPassThru.node.attributes.artifactId,
                          version : options.cbPassThru.node.attributes.version,
                          repoId : options.cbPassThru.node.attributes.repositoryId,
                          classifier : options.cbPassThru.node.attributes.classifier,
                          extension : options.cbPassThru.node.attributes.extension,
                          artifactLink : options.cbPassThru.node.attributes.artifactUri,
                          pomLink : options.cbPassThru.node.attributes.pomUri,
                          nodeName : options.cbPassThru.node.attributes.nodeName
                        });
                  }
                },
                url : Sonatype.config.servicePath + '/artifact/maven/resolve',
                params : {
                  r : node.attributes.repositoryId,
                  g : node.attributes.groupId,
                  a : node.attributes.artifactId,
                  v : node.attributes.version,
                  c : node.attributes.classifier,
                  e : node.attributes.extension,
                  isLocal : 'true'
                }
              });
          // var resourceURI = node.ownerTree.loader.url.substring(0,
          // node.ownerTree.loader.url.length - 'index_content'.length) +
          // 'content' + node.attributes.path;
        }
        else
        {
          passthru.container.artifactContainer.updateArtifact(null);
        }
      }
    });
/*
 * Copyright (c) 2008-2011 Sonatype, Inc.
 * All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
 *
 * This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
 * Public License Version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License Version 3
 * for more details.
 *
 * You should have received a copy of the GNU Affero General Public License Version 3 along with this program.  If not, see
 * http://www.gnu.org/licenses.
 *
 * Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
 * Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
 * All other trademarks are the property of their respective owners.
 */
var SEARCH_FIELD_CONFIG = {
  xtype : 'trigger',
  triggerClass : 'x-form-search-trigger',
  listeners : {
    'specialkey' : {
      fn : function(f, e) {
        if (e.getKey() == e.ENTER)
        {
          this.onTriggerClick();
        }
      }
    }
  },
  onTriggerClick : function(a, b, c) {
    var v = this.getRawValue();
    if (v.length > 0)
    {
      var panel = Sonatype.view.mainTabPanel.addOrShowTab('nexus-search', Sonatype.repoServer.SearchPanel, {
            title : 'Search'
          });
      panel.startQuickSearch(v);
      // window.location = 'index.html#nexus-search;quick~' + v;
    }
  }
};

Sonatype.Events.addListener('nexusNavigationInit', function(nexusPanel) {
      if (Sonatype.lib.Permissions.checkPermission('nexus:index', Sonatype.lib.Permissions.READ))
      {
        nexusPanel.insert(0,{
              title : 'Artifact Search',
              id : 'st-nexus-search',
              items : [Ext.apply({
                        repoPanel : this,
                        id : 'quick-search--field',
                        width : 140
                      }, SEARCH_FIELD_CONFIG), {
                    title : 'Advanced Search',
                    tabCode : Sonatype.repoServer.SearchPanel,
                    tabId : 'nexus-search',
                    tabTitle : 'Search'
                  }]
            });
      }
    });

Sonatype.Events.addListener('welcomePanelInit', function(repoServer, welcomePanelConfig) {
      if (Sonatype.lib.Permissions.checkPermission('nexus:index', Sonatype.lib.Permissions.READ))
      {
        welcomePanelConfig.items.push({
              layout : 'form',
              border : false,
              frame : false,
              labelWidth : 10,
              items : [{
                    border : false,
                    html : '<div class="little-padding">' + 'Type in the name of a project, class, or artifact into the text box ' + 'below, and click Search. Use "Advanced Search" on the left for more options.' + '</div>'
                  }, Ext.apply({
                        repoPanel : repoServer,
                        id : 'quick-search-welcome-field',
                        anchor : '-10',
                        labelSeparator : ''
                      }, SEARCH_FIELD_CONFIG)]
            });
      }
    });

Sonatype.Events.addListener('welcomeTabRender', function() {
      var c = Ext.getCmp('quick-search-welcome-field');
      if (c)
      {
        c.focus(true, 100);
      }
    });

