text: /**********************************************************************
  
     Audacity - A Digital Audio Editor
     Copyright 1999-2009 Audacity Team
     License: wxwidgets
  
     Dan Horgan
  
  ******************************************************************//**
  
  \file CommandTargets.cpp
  \brief Contains definitions for CommandType class
  
  \class InteractiveOutputTargets
  \brief InteractiveOutputTargets is an output target that pops up a 
  dialog, if necessary.
  
  \class LongMessageDialog
  \brief LongMessageDialog is a dialog with a Text Window in it to 
  capture the more lengthy output from some commands.
  
  *//*******************************************************************/
  
  
  #include "CommandTargets.h"
  
  #include <wx/app.h>
  #include <wx/statusbr.h>
  #include <wx/string.h>
  #include <wx/textctrl.h>
  #include "../ShuttleGui.h"
  #include "../widgets/AudacityMessageBox.h"
  #include "../widgets/wxPanelWrapper.h"
  
  #include <locale>
  #include <sstream>
  
  void CommandMessageTarget::StartArray()
  {
     wxString Padding;
     Padding.Pad( mCounts.size() *2 -2);
     Update( wxString::Format( "%s%s[ ", ( mCounts.back() > 0 ) ? ",\n" : "\n", Padding ));
     mCounts.back() += 1;
     mCounts.push_back( 0 );
  }
  
  void CommandMessageTarget::EndArray(){
     if( mCounts.size() > 1 ){
        mCounts.pop_back();
     }
     Update( " ]" );
  }
  void CommandMessageTarget::StartStruct(){
     wxString Padding;
     Padding.Pad( mCounts.size() *2 -2);
     Update( wxString::Format( "%s%s{ ", ( mCounts.back() > 0 ) ? ",\n" : "\n", Padding ));
     mCounts.back() += 1;
     mCounts.push_back( 0 );
  }
  void CommandMessageTarget::EndStruct(){
     if( mCounts.size() > 1 ){
        mCounts.pop_back();
     }
     Update( " }" );
  }
  void CommandMessageTarget::AddItem(const wxString &value, const wxString &name){
     wxString Padding;
     Padding.Pad( mCounts.size() *2 -2);
     Padding = (( value.length() < 15 ) || (mCounts.back()<=0))  ? "" : wxString("\n") + Padding;
     if( name.empty() )
        Update( wxString::Format( "%s%s\"%s\"", (mCounts.back()>0)?", ":"", Padding, Escaped(value)));
     else
        Update( wxString::Format( "%s%s\"%s\":\"%s\"", (mCounts.back()>0)?", ":"", Padding, name, Escaped(value)));
     mCounts.back() += 1;
  }
  
  void CommandMessageTarget::AddBool(const bool value,      const wxString &name){
     if( name.empty() )
        Update( wxString::Format( "%s\"%s\"", (mCounts.back()>0)?", ":"", value?"true":"false"));
     else
        Update( wxString::Format( "%s\"%s\":\"%s\"", (mCounts.back()>0)?", ":"", name,value?"true":"false"));
     mCounts.back() += 1;
  }
  
  void CommandMessageTarget::AddItem(const double value,    const wxString &name){
     std::stringstream str;
     std::locale nolocale("C");
     str.imbue(nolocale);
  
     if( name.empty() )
        str << ((mCounts.back()>0)? ", " : "") << value;
     else
        str << ((mCounts.back()>0)? ", " : "") << "\"" << name << "\"" << ":" << value;
  
     Update( str.str() );
     mCounts.back() += 1;
  }
  
  void CommandMessageTarget::StartField(const wxString &name){
     if( name.empty() )
        Update( wxString::Format( "%s", (mCounts.back()>0)? ", " : ""));
     else
        Update( wxString::Format( "%s\"%s\":", (mCounts.back()>0) ?", ":"", name));
     mCounts.back() += 1;
     mCounts.push_back( 0 );
  }
  
  void CommandMessageTarget::EndField(){
     if( mCounts.size() > 1 ){
        mCounts.pop_back();
     }
  }
  
  void CommandMessageTarget::Flush(){
  }
  
  wxString CommandMessageTarget::Escaped( const wxString & str){
     wxString Temp = str;
     Temp.Replace( "\"", "\\\"");
     return Temp;
  }
  
  
  
  void LispyCommandMessageTarget::StartArray()
  {
     wxString Padding;
     Padding.Pad( mCounts.size() *2 -2);
     Update( wxString::Format( (mCounts.back()>0)?"\n%s(":"(", Padding ));
     mCounts.back() += 1;
     mCounts.push_back( 0 );
  }
  
  void LispyCommandMessageTarget::EndArray(){
     if( mCounts.size() > 1 ){
        mCounts.pop_back();
     }
     Update( ")" );
  }
  void LispyCommandMessageTarget::StartStruct(){
     wxString Padding;
     Padding.Pad( mCounts.size() *2 -2);
     Update( wxString::Format( (mCounts.back()>0)?"\n%s(":"(", Padding ));
     mCounts.back() += 1;
     mCounts.push_back( 0 );
  }
  void LispyCommandMessageTarget::EndStruct(){
     if( mCounts.size() > 1 ){
        mCounts.pop_back();
     }
     Update( ")" );
  }
  void LispyCommandMessageTarget::AddItem(const wxString &value, const wxString &name){
     wxString Padding;
     if( name.empty() )
        Update( wxString::Format( "%s%s\"%s\"", (mCounts.back()>0)?" ":"", Padding, Escaped(value)));
     else 
        Update( wxString::Format( "%s%s(%s \"%s\")", (mCounts.back()>0)?" ":"", Padding, name, Escaped(value)));
     mCounts.back() += 1;
  }
  void LispyCommandMessageTarget::AddBool(const bool value,      const wxString &name){
     if( name.empty() )
        Update( wxString::Format( "%s%s", (mCounts.back()>0)?" ":"",value?"True":"False"));
     else 
        Update( wxString::Format( "%s(%s %s)", (mCounts.back()>0)?" ":"", name,value?"True":"False"));
     mCounts.back() += 1;
  }
  void LispyCommandMessageTarget::AddItem(const double value,    const wxString &name){
     if( name.empty() )
        Update( wxString::Format( "%s%g", (mCounts.back()>0)?" ":"", value));
     else 
        Update( wxString::Format( "%s(%s %g)", (mCounts.back()>0)?" ":"", name,value));
     mCounts.back() += 1;
  }
  
  void LispyCommandMessageTarget::StartField(const wxString &name){
     Update( wxString::Format( "%s(%s", (mCounts.back()>0)?" ":"", name ));
     mCounts.back() += 1;
     mCounts.push_back( 0 );
  }
  
  void LispyCommandMessageTarget::EndField(){
     if( mCounts.size() > 1 ){
        mCounts.pop_back();
     }
     Update( ")" );
  }
  
  
  
  
  
  
  void BriefCommandMessageTarget::StartArray()
  {
     wxString Padding;
     Padding.Pad( mCounts.size() *2 -2);
     if( mCounts.size() <= 3 )
        Update( wxString::Format( "%s%s ", ( mCounts.back() > 0 ) ? " \n" : "", Padding ));
     mCounts.back() += 1;
     mCounts.push_back( 0 );
  }
  
  void BriefCommandMessageTarget::EndArray(){
     if( mCounts.size() > 1 ){
        mCounts.pop_back();
     }
     if( mCounts.size() <= 3 )
       Update( " " );
  }
  void BriefCommandMessageTarget::StartStruct(){
     wxString Padding;
     Padding.Pad( mCounts.size() *2 -2);
     if( mCounts.size() <= 3 )
        Update( wxString::Format( "%s%s ", ( mCounts.back() > 0 ) ? " \n" : "", Padding ));
     mCounts.back() += 1;
     mCounts.push_back( 0 );
  }
  void BriefCommandMessageTarget::EndStruct(){
     if( mCounts.size() > 1 ){
        mCounts.pop_back();
     }
     if( mCounts.size() <= 3 )
        Update( " " );
  }
  void BriefCommandMessageTarget::AddItem(const wxString &value, const wxString &WXUNUSED(name)){
     if( mCounts.size() <= 3 )
        Update( wxString::Format( "%s\"%s\"", (mCounts.back()>0)?" ":"",Escaped(value)));
     mCounts.back() += 1;
  }
  void BriefCommandMessageTarget::AddBool(const bool value,      const wxString &WXUNUSED(name)){
     if( mCounts.size() <= 3 )
        Update( wxString::Format( "%s%s", (mCounts.back()>0)?" ":"",value?"True":"False"));
     mCounts.back() += 1;
  }
  void BriefCommandMessageTarget::AddItem(const double value,    const wxString &WXUNUSED(name)){
     if( mCounts.size() <= 3 )
        Update( wxString::Format( "%s%g", (mCounts.back()>0)?" ":"", value));
     mCounts.back() += 1;
  }
  
  void BriefCommandMessageTarget::StartField(const wxString &WXUNUSED(name)){
     mCounts.back() += 1;
     mCounts.push_back( 0 );
  }
  
  void BriefCommandMessageTarget::EndField(){
     if( mCounts.size() > 1 ){
        mCounts.pop_back();
     }
  }
  
  
  void MessageBoxTarget::Update(const wxString &message)
  {
     // Should these messages be localized?
     AudacityMessageBox( Verbatim( message ) );
  }
  
  
  LispifiedCommandOutputTargets::LispifiedCommandOutputTargets( CommandOutputTargets & target )
   : CommandOutputTargets() ,
     pToRestore( &target )
  {
     mProgressTarget = std::move(target.mProgressTarget), 
     mStatusTarget = std::make_shared<LispyCommandMessageTarget>( *target.mStatusTarget.get() ), 
     mErrorTarget = std::move( target.mErrorTarget );
  }
  
  LispifiedCommandOutputTargets::~LispifiedCommandOutputTargets()
  {
     pToRestore->mProgressTarget = std::move( mProgressTarget );
     //The status was never captured so does not need restoring.
     //pToRestore->mStatusTarget = std::move( mStatusTarget );
     pToRestore->mErrorTarget = std::move( mErrorTarget );
  }
  
  BriefCommandOutputTargets::BriefCommandOutputTargets( CommandOutputTargets & target )
   : CommandOutputTargets() ,
     pToRestore( &target )
  {
     mProgressTarget = std::move(target.mProgressTarget), 
     mStatusTarget = std::make_shared<BriefCommandMessageTarget>( *target.mStatusTarget.get() ), 
     mErrorTarget = std::move( target.mErrorTarget );
  }
  
  BriefCommandOutputTargets::~BriefCommandOutputTargets()
  {
     pToRestore->mProgressTarget = std::move( mProgressTarget );
     //The status was never captured so does not need restoring.
     //pToRestore->mStatusTarget = std::move( mStatusTarget );
     pToRestore->mErrorTarget = std::move( mErrorTarget );
  }
  
  
  
  
  
  
  
  
  
  
  
  class AUDACITY_DLL_API LongMessageDialog /* not final */ : public wxDialogWrapper
  {
  public:
     // constructors and destructors
     LongMessageDialog(wxWindow * parent,
                  const TranslatableString & title,
                  int type = 0,
                  int flags = wxDEFAULT_DIALOG_STYLE,
                  int additionalButtons = 0);
     ~LongMessageDialog();
  
     bool Init();
     virtual void OnOk(wxCommandEvent & evt);
     virtual void OnCancel(wxCommandEvent & evt);
  
     static void AcceptText( const wxString & Text );
     static void Flush();
  
     wxTextCtrl * mTextCtrl;
     wxString mText;
     static LongMessageDialog * pDlg;
  private:
     int mType;
     int mAdditionalButtons;
  
     DECLARE_EVENT_TABLE()
     wxDECLARE_NO_COPY_CLASS(LongMessageDialog);
  };
  
  
  LongMessageDialog * LongMessageDialog::pDlg = NULL;
  
  
  BEGIN_EVENT_TABLE(LongMessageDialog, wxDialogWrapper)
     EVT_BUTTON(wxID_OK, LongMessageDialog::OnOk)
  END_EVENT_TABLE()
  
  LongMessageDialog::LongMessageDialog(wxWindow * parent,
                             const TranslatableString & title,
                             int type,
                             int flags,
                             int additionalButtons)
  : wxDialogWrapper(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, flags | wxRESIZE_BORDER)
  {
     mType = type;
     mAdditionalButtons = additionalButtons;
     SetName(XO("Long Message"));
     // The long message adds lots of short strings onto this one.
     // So preallocate to make it faster.
     // Needs 37Kb for all commands.
     mText.Alloc(40000);
  }
  
  LongMessageDialog::~LongMessageDialog(){
     pDlg = NULL;
  }
  
  
  bool LongMessageDialog::Init()
  {
     ShuttleGui S(this, eIsCreating);
  
     S.SetBorder(5);
     S.StartVerticalLay(true);
     {
        mTextCtrl = S.AddTextWindow( "" );
        long buttons = eOkButton;
        S.AddStandardButtons(buttons|mAdditionalButtons);
     }
     S.EndVerticalLay();
  
     Layout();
     Fit();
     SetMinSize(wxSize(600,350));
     Center();
     return true;
  }
  
  void LongMessageDialog::OnOk(wxCommandEvent & WXUNUSED(evt)){
     //Close(true);
     Destroy();
  }
  
  void LongMessageDialog::OnCancel(wxCommandEvent & WXUNUSED(evt)){
     //Close(true);
     Destroy();
  }
  
  void LongMessageDialog::AcceptText( const wxString & Text )
  {
     if( pDlg == NULL ){
        pDlg = new LongMessageDialog(
           wxTheApp->GetTopWindow(), XO( "Long Message" ) );
        pDlg->Init();
        pDlg->Show();
     }
     pDlg->mText = pDlg->mText + Text;
  }
  
  void LongMessageDialog::Flush()
  {
     if( pDlg ){
        if( !pDlg->mText.EndsWith( "\n\n" ))
        {
           pDlg->mText += "\n\n";
           pDlg->mTextCtrl->SetValue( pDlg->mText );
           pDlg->mTextCtrl->ShowPosition( pDlg->mTextCtrl->GetLastPosition() );
        }
     }
  }
  
  
  
  
  
  
  /** 
  CommandMessageTarget that displays messages from a command in the 
  LongMessageDialog
  */
  class MessageDialogTarget final : public CommandMessageTarget
  {
  public:
     virtual ~MessageDialogTarget() {Flush();}
     void Update(const wxString &message) override
     {
        LongMessageDialog::AcceptText(message);
     }
     void Flush() override
     {
        LongMessageDialog::Flush();
     }
  };
  
  
  
  /// Extended Target Factory with more options.
  class ExtTargetFactory : public TargetFactory
  {
  public:
     static std::shared_ptr<CommandMessageTarget> LongMessages()
     {
        return std::make_shared<MessageDialogTarget>();
     }
  };
  
  
  
  InteractiveOutputTargets::InteractiveOutputTargets() : 
     CommandOutputTargets( 
        ExtTargetFactory::ProgressDefault(), 
        ExtTargetFactory::LongMessages(), 
        ExtTargetFactory::MessageDefault()
     )
  {
  }
  
  void StatusBarTarget::Update(const wxString &message)
  {
     mStatus.SetStatusText(message, 0);
  }
  