/**********************************************************************

Audacity: A Digital Audio Editor

BackgroundCell.cpp

Paul Licameli split from TrackPanel.cpp

**********************************************************************/


#include "BackgroundCell.h"

#include "AColor.h"
#include "../../HitTestResult.h"
#include "Project.h"
#include "../../RefreshCode.h"
#include "SelectionState.h"
#include "Track.h"
#include "../../TrackArtist.h"
#include "../../TrackPanel.h"
#include "../../TrackPanelConstants.h"
#include "../../TrackPanelDrawingContext.h"
#include "../../TrackPanelMouseEvent.h"
#include "../../UIHandle.h"
#include "ViewInfo.h"

#include <wx/cursor.h>

// Define this, just so the click to deselect can dispatch here
// This handle class, unlike most, doesn't associate with any particular cell.
class BackgroundHandle : public UIHandle
{
   BackgroundHandle(const BackgroundHandle&) = delete;
   BackgroundHandle &operator=(const BackgroundHandle&) = delete;

public:
   BackgroundHandle() {}

   BackgroundHandle(BackgroundHandle&&) = default;
   BackgroundHandle& operator=(BackgroundHandle&&) = default;

   static HitTestPreview HitPreview()
   {
      static wxCursor arrowCursor{ wxCURSOR_ARROW };
      return { {}, &arrowCursor };
   }

   virtual ~BackgroundHandle()
   {}

   std::shared_ptr<const Track> FindTrack() const override
   { return nullptr; }

   Result Click
      (const TrackPanelMouseEvent &evt, AudacityProject *pProject) override
   {
      using namespace RefreshCode;
      const wxMouseEvent &event = evt.event;
      // Do not start a drag
      Result result = Cancelled;

      // AS: If the user clicked outside all tracks, make nothing
      //  selected.
      if ((event.ButtonDown() || event.ButtonDClick())) {
         SelectionState::Get( *pProject ).SelectNone(
            TrackList::Get( *pProject ) );
         result |= RefreshAll;
      }

      return result;
   }

   Result Drag
      (const TrackPanelMouseEvent &, AudacityProject *) override
   { return RefreshCode::RefreshNone; }

   HitTestPreview Preview
      (const TrackPanelMouseState &, AudacityProject *) override
   { return HitPreview(); }

   Result Release
      (const TrackPanelMouseEvent &, AudacityProject *,
       wxWindow *) override
   { return RefreshCode::RefreshNone; }

   Result Cancel(AudacityProject *) override
   { return RefreshCode::RefreshNone; }
};

static const AudacityProject::AttachedObjects::RegisteredFactory key{
  []( AudacityProject &parent ){
     auto result = std::make_shared< BackgroundCell >( &parent );
     TrackPanel::Get( parent ).SetBackgroundCell( result );
     return result;
   }
};

BackgroundCell &BackgroundCell::Get( AudacityProject &project )
{
   return project.AttachedObjects::Get< BackgroundCell >( key );
}

const BackgroundCell &BackgroundCell::Get( const AudacityProject &project )
{
   return Get( const_cast< AudacityProject & >( project ) );
}

BackgroundCell::~BackgroundCell()
{
}

std::vector<UIHandlePtr> BackgroundCell::HitTest
(const TrackPanelMouseState &,
 const AudacityProject *)
{
   auto result = AssignUIHandlePtr(mHandle, std::make_shared<BackgroundHandle>());
   return { result };
}

std::shared_ptr<Track> BackgroundCell::DoFindTrack()
{
   return {};
}

void BackgroundCell::Draw(
   TrackPanelDrawingContext &context,
   const wxRect &rect, unsigned iPass )
{
   if ( iPass == TrackArtist::PassBackground ) {
      auto &dc = context.dc;
      // Paint over the part below the tracks
      AColor::TrackPanelBackground( &dc, false );
      dc.DrawRectangle( rect );
   }
}

wxRect BackgroundCell::DrawingArea(
   TrackPanelDrawingContext &,
   const wxRect &rect, const wxRect &, unsigned iPass )
{
   if ( iPass == TrackArtist::PassBackground )
      // If there are any tracks, extend the drawing area up, to cover the
      // bottom ends of any zooming guide lines.
      return {
         rect.x,
         rect.y - kTopMargin,
         rect.width,
         rect.height + kTopMargin
      };
   else
      return rect;
}

auto BackgroundCell::GetMenuItems(
   const wxRect &, const wxPoint *, AudacityProject * )
      -> std::vector<MenuItem>
{
   // These commands exist in toolbar menus too, but maybe with other labels
   // TODO: devise a system of registration so that BackgroundCell has no
   // special knowledge about track sub-types
   return {
      { L"NewMonoTrack", XO("Add Mono Track")},
      { L"NewStereoTrack", XO("Add Stereo Track") },
      { L"NewLabelTrack", XO("Add Label Track"),  },
      {},
      { L"Export", XO("Export Audio..."),  },
      {},
      { L"SelectAll", XO("Select All") },
   };
}
