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

  Audacity: A Digital Audio Editor

  ProgressDialog.h

  Copyright
     Leland Lucius
     Vaughan Johnson

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

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

#ifndef __AUDACITY_WIDGETS_PROGRESSDIALOG__
#define __AUDACITY_WIDGETS_PROGRESSDIALOG__

#include <chrono>

#include <vector>
#include <wx/defs.h>
#include <wx/evtloop.h> // member variable

#include "wxPanelWrapper.h" // to inherit

#include "BasicUI.h" // For ProgressResult
using ProgressResult = BasicUI::ProgressResult;

class wxGauge;
class wxStaticText;

enum ProgressDialogFlags
{
   pdlgEmptyFlags = 0x00000000,
   pdlgHideStopButton = 0x00000001,
   pdlgHideCancelButton = 0x00000002,
   pdlgHideElapsedTime = 0x00000004,
   pdlgConfirmStopCancel = 0x00000008,

   pdlgDefaultFlags = pdlgEmptyFlags
};

////////////////////////////////////////////////////////////
/// ProgressDialog Class
////////////////////////////////////////////////////////////

class WX_INIT_API ProgressDialog /* not final */ :
    public wxDialogWrapper,
    public BasicUI::ProgressDialog
{
public:
   ProgressDialog();

   // Display a simple message.
   ProgressDialog(const TranslatableString & title,
                  const TranslatableString & message = {},
                  int flags = pdlgDefaultFlags,
                  const TranslatableString & sRemainingLabelText = {});

   using MessageColumn = std::vector< TranslatableString >;
   using MessageTable = std::vector< MessageColumn >;

protected:
   // Display a table of messages.
   // Each member of the table is a column of messages.
   // Each member of a column is a string that should have no newlines,
   // and each column should have the same number of elements, to make
   // proper correspondences, but this is not checked.
   ProgressDialog(const TranslatableString & title,
                  const MessageTable & columns,
                  int flags = pdlgDefaultFlags,
                  const TranslatableString & sRemainingLabelText = {});

public:
   virtual ~ProgressDialog();

   bool Create(const TranslatableString & title,
               const TranslatableString & message = {},
               int flags = pdlgDefaultFlags,
               const TranslatableString & sRemainingLabelText = {});

   void Reinit() override;

   void SetDialogTitle(const TranslatableString& title) override;

protected:
   bool Create(const TranslatableString & title,
               const MessageTable & columns,
               int flags = pdlgDefaultFlags,
               const TranslatableString & sRemainingLabelText = {});

public:
   ProgressResult Update(int value, const TranslatableString & message = {});
   ProgressResult Update(double current, const TranslatableString & message = {});
   ProgressResult Update(double current, double total, const TranslatableString & message = {});
   ProgressResult Update(wxULongLong_t current, wxULongLong_t total, const TranslatableString & message = {});
   ProgressResult Update(wxLongLong current, wxLongLong total, const TranslatableString & message = {});
   ProgressResult Update(wxLongLong_t current, wxLongLong_t total, const TranslatableString & message = {});
   ProgressResult Update(int current, int total, const TranslatableString & message = {});
   
   ProgressResult Poll(
      unsigned long long numerator, unsigned long long denominator,
      const TranslatableString& message = {}) override;
      
   void SetMessage(const TranslatableString & message) override;

protected:
   wxWindowRef mHadFocus;

   wxStaticText *mElapsed;
   wxStaticText *mRemaining;
   wxGauge *mGauge;

   wxLongLong_t mStartTime;
   wxLongLong_t mLastUpdate;
   wxLongLong_t mYieldTimer;
   wxLongLong_t mElapsedTime {};
   int mLastValue; // gauge value, range = [0,1000]

   bool mCancel;
   bool mStop;

   bool mIsTransparent;

   // MY: Booleans to hold the flag values
   bool m_bShowElapsedTime = true;
   bool m_bConfirmAction = false;

private:
   void Init();
   bool SearchForWindow(const wxWindowList & list, const wxWindow *searchfor) const;
   void OnCancel(wxCommandEvent & e);
   void OnStop(wxCommandEvent & e);
   void OnCloseWindow(wxCloseEvent & e);
   void Beep() const;
   
   bool ConfirmAction(const TranslatableString & sPrompt,
                      const TranslatableString & sTitle,
                      int iButtonID = -1);

   void AddMessageAsColumn(wxBoxSizer * pSizer,
                           const MessageColumn &column, bool bFirstColumn);

private:
   // This guarantees we have an active event loop...possible during OnInit()
   wxEventLoopGuarantor mLoop;

   std::unique_ptr<wxWindowDisabler> mDisable;

   wxStaticText *mMessage{} ;
   int mLastW{ 0 };
   int mLastH{ 0 };

   std::chrono::nanoseconds mTotalPollTime {};
   unsigned mPollsCount { 0 };
   std::chrono::nanoseconds mTotalYieldTime {};
   unsigned mYieldsCount { 0 };

   DECLARE_EVENT_TABLE()
};

class WX_INIT_API TimerProgressDialog final : public ProgressDialog
{
public:
   TimerProgressDialog(const wxLongLong_t duration,
                       const TranslatableString &title,
                       const MessageTable & columns,
                       int flags = pdlgDefaultFlags,
                       const TranslatableString & sRemainingLabelText = {});

   // Oh no, there is an inherited nullary "Update" in wxDialog!
   // Choose another name then...
   ProgressResult UpdateProgress();

protected:
   wxLongLong_t mDuration;

   // Disallow direct use of the inherited overloads of Update because it
   // doesn't support changes of message
   using ProgressDialog::Update;
};

#endif
