#include "SendToPrinter.hpp"
#include "I18N.hpp"

#include "libslic3r/Utils.hpp"
#include "libslic3r/Thread.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "GUI_Preview.hpp"
#include "MainFrame.hpp"
#include "format.hpp"
#include "Widgets/ProgressDialog.hpp"
#include "ReleaseNote.hpp"
#include "Widgets/RoundedRectangle.hpp"
#include "Widgets/StaticBox.hpp"
#include "ConnectPrinter.hpp"

#include <wx/progdlg.h>
#include <wx/clipbrd.h>
#include <wx/dcgraph.h>
#include <miniz.h>
#include <algorithm>
#include "BitmapCache.hpp"

#include "slic3r/Utils/QDTUtil.hpp"

namespace Slic3r {
namespace GUI {

#define INITIAL_NUMBER_OF_MACHINES 0
#define LIST_REFRESH_INTERVAL 200
#define MACHINE_LIST_REFRESH_INTERVAL 2000
#define EMMC_STORAGE "emmc"

constexpr int timeout_period = 15000; // ms

wxDEFINE_EVENT(EVT_UPDATE_USER_MACHINE_LIST, wxCommandEvent);
wxDEFINE_EVENT(EVT_PRINT_JOB_CANCEL, wxCommandEvent);
wxDEFINE_EVENT(EVT_SEND_JOB_SUCCESS, wxCommandEvent);
wxDEFINE_EVENT(EVT_CLEAR_IPADDRESS, wxCommandEvent);

void SendToPrinterDialog::stripWhiteSpace(std::string& str)
{
    if (str == "") { return; }

    string::iterator cur_it;
    cur_it = str.begin();

    while (cur_it != str.end()) {
        if ((*cur_it) == '\n' || (*cur_it) == ' ') {
            cur_it = str.erase(cur_it);
        }
        else {
            cur_it++;
        }
    }
}

wxString SendToPrinterDialog::format_text(wxString &m_msg)
{

	if (wxGetApp().app_config->get("language") != "zh_CN") { return m_msg; }

	wxString out_txt = m_msg;
	wxString count_txt = "";
	int      new_line_pos = 0;

	for (int i = 0; i < m_msg.length(); i++) {
		auto text_size = m_statictext_printer_msg->GetTextExtent(count_txt);
		if (text_size.x < (FromDIP(400))) {
			count_txt += m_msg[i];
		}
		else {
			out_txt.insert(i - 1, '\n');
			count_txt = "";
		}
	}
	return out_txt;
}

void SendToPrinterDialog::check_focus(wxWindow* window)
{
    if (window == m_rename_input || window == m_rename_input->GetTextCtrl()) {
        on_rename_enter();
    }
}

void SendToPrinterDialog::check_fcous_state(wxWindow* window)
{
    check_focus(window);
    auto children = window->GetChildren();
    for (auto child : children) {
        check_fcous_state(child);
    }
}

void SendToPrinterDialog::on_rename_click(wxCommandEvent& event)
{
    m_is_rename_mode = true;
    m_rename_input->GetTextCtrl()->SetValue(m_current_project_name);
    m_rename_switch_panel->SetSelection(1);
    m_rename_input->GetTextCtrl()->SetFocus();
    m_rename_input->GetTextCtrl()->SetInsertionPointEnd();
}

void SendToPrinterDialog::on_rename_enter()
{
    if (m_is_rename_mode == false) {
        return;
    }
    else {
        m_is_rename_mode = false;
    }

    auto     new_file_name = m_rename_input->GetTextCtrl()->GetValue();

    wxString temp;
    int      num = 0;
    for (auto t : new_file_name) {
        if (t == wxString::FromUTF8("\x20")) {
            num++;
            if (num == 1) temp += t;
        } else {
            num = 0;
            temp += t;
        }
    }
    new_file_name = temp;

    auto     m_valid_type = Valid;
    wxString info_line;

    //y51
    const char* unusable_symbols = "<>[]:\\|?*\"";

    const std::string unusable_suffix = PresetCollection::get_suffix_modified(); //"(modified)";
    for (size_t i = 0; i < std::strlen(unusable_symbols); i++) {
        if (new_file_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
            info_line = _L("Name is invalid;") + "\n" + _L("illegal characters:") + " " + unusable_symbols;
            m_valid_type = NoValid;
            break;
        }
    }

    if (m_valid_type == Valid && new_file_name.find(unusable_suffix) != std::string::npos) {
        info_line = _L("Name is invalid;") + "\n" + _L("illegal suffix:") + "\n\t" + from_u8(PresetCollection::get_suffix_modified());
        m_valid_type = NoValid;
    }

    if (m_valid_type == Valid && new_file_name.empty()) {
        info_line = _L("The name is not allowed to be empty.");
        m_valid_type = NoValid;
    }

    if (m_valid_type == Valid && new_file_name.find_first_of(' ') == 0) {
        info_line = _L("The name is not allowed to start with space character.");
        m_valid_type = NoValid;
    }

    if (m_valid_type == Valid && new_file_name.find_last_of(' ') == new_file_name.length() - 1) {
        info_line = _L("The name is not allowed to end with space character.");
        m_valid_type = NoValid;
    }

    if (m_valid_type == Valid && new_file_name.size() >= 100) {
        info_line    = _L("The name length exceeds the limit.");
        m_valid_type = NoValid;
    }

    if (m_valid_type != Valid) {
        MessageDialog msg_wingow(nullptr, info_line, "", wxICON_WARNING | wxOK);
        if (msg_wingow.ShowModal() == wxID_OK) {
            m_rename_switch_panel->SetSelection(0);
            m_rename_text->SetLabel(m_current_project_name);
            m_rename_normal_panel->Layout();
            return;
        }
    }

    m_current_project_name = new_file_name;
    m_rename_switch_panel->SetSelection(0);
    m_rename_text->SetLabel(m_current_project_name);
    m_rename_normal_panel->Layout();
}

SendToPrinterDialog::SendToPrinterDialog(Plater *plater)
    : DPIDialog(static_cast<wxWindow *>(wxGetApp().mainframe), wxID_ANY, _L("Send to Printer storage"), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
    , m_plater(plater), m_export_3mf_cancel(false)
{
#ifdef __WINDOWS__
    SetDoubleBuffered(true);
#endif //__WINDOWS__

    //y24
    m_isNetMode = wxGetApp().app_config->get("machine_list_net") == "1";
    PresetBundle& preset_bundle = *wxGetApp().preset_bundle;
    preset_typename = preset_bundle.printers.get_edited_preset().get_printer_type(&preset_bundle);
    preset_typename_normalized = NormalizeVendor(preset_typename);

    // bind
    Bind(wxEVT_CLOSE_WINDOW, &SendToPrinterDialog::on_cancel, this);

    // font
    SetFont(wxGetApp().normal_font());

    // icon
    std::string icon_path = (boost::format("%1%/images/QIDIStudioTitle.ico") % resources_dir()).str();
    SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));

    Freeze();
    SetBackgroundColour(m_colour_def_color);

    m_sizer_main = new wxBoxSizer(wxVERTICAL);

    m_sizer_main->SetMinSize(wxSize(0, -1));
    m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL);
    m_line_top->SetBackgroundColour(wxColour(166, 169, 170));

    m_scrollable_region       = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
    m_sizer_scrollable_region = new wxBoxSizer(wxVERTICAL);

    m_panel_image = new wxPanel(m_scrollable_region, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
    m_panel_image->SetBackgroundColour(m_colour_def_color);

    sizer_thumbnail = new wxBoxSizer(wxVERTICAL);
    m_thumbnailPanel = new ThumbnailPanel(m_panel_image);
    m_thumbnailPanel->SetSize(wxSize(FromDIP(256), FromDIP(256)));
    m_thumbnailPanel->SetMinSize(wxSize(FromDIP(256), FromDIP(256)));
    m_thumbnailPanel->SetMaxSize(wxSize(FromDIP(256), FromDIP(256)));
    sizer_thumbnail->Add(m_thumbnailPanel, 0, wxEXPAND, 0);
    m_panel_image->SetSizer(sizer_thumbnail);
    m_panel_image->Layout();

    wxBoxSizer *m_sizer_basic        = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer *m_sizer_basic_weight = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer *m_sizer_basic_time   = new wxBoxSizer(wxHORIZONTAL);

    auto timeimg = new wxStaticBitmap(m_scrollable_region, wxID_ANY, create_scaled_bitmap("print-time", this, 18), wxDefaultPosition, wxSize(FromDIP(18), FromDIP(18)), 0);
    m_sizer_basic_weight->Add(timeimg, 1, wxEXPAND | wxALL, FromDIP(5));
    m_stext_time = new wxStaticText(m_scrollable_region, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
    m_sizer_basic_weight->Add(m_stext_time, 0, wxALL, FromDIP(5));
    m_sizer_basic->Add(m_sizer_basic_weight, 0, wxALIGN_CENTER, 0);
    m_sizer_basic->Add(0, 0, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));

    auto weightimg = new wxStaticBitmap(m_scrollable_region, wxID_ANY, create_scaled_bitmap("print-weight", this, 18), wxDefaultPosition, wxSize(FromDIP(18), FromDIP(18)), 0);
    m_sizer_basic_time->Add(weightimg, 1, wxEXPAND | wxALL, FromDIP(5));
    m_stext_weight = new wxStaticText(m_scrollable_region, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
    m_sizer_basic_time->Add(m_stext_weight, 0, wxALL, FromDIP(5));
    m_sizer_basic->Add(m_sizer_basic_time, 0, wxALIGN_CENTER, 0);

    m_line_materia = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1), wxTAB_TRAVERSAL);
    m_line_materia->SetForegroundColour(wxColour(238, 238, 238));
    m_line_materia->SetBackgroundColour(wxColour(238, 238, 238));

    wxBoxSizer *m_sizer_printer = new wxBoxSizer(wxHORIZONTAL);

    m_stext_printer_title = new wxStaticText(this, wxID_ANY, _L("Printer"), wxDefaultPosition, wxSize(-1, -1), 0);
    m_stext_printer_title->SetFont(::Label::Head_14);
    m_stext_printer_title->Wrap(-1);
    m_stext_printer_title->SetForegroundColour(m_colour_bold_color);
    m_stext_printer_title->SetBackgroundColour(m_colour_def_color);

    m_sizer_printer->Add(m_stext_printer_title, 0, wxALL | wxLEFT, FromDIP(5));
    m_sizer_printer->Add(0, 0, 0, wxEXPAND | wxLEFT, FromDIP(12));

    m_comboBox_printer = new ::ComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(FromDIP(250), -1), 0, nullptr, wxCB_READONLY);
    m_comboBox_printer->Bind(wxEVT_COMBOBOX, &SendToPrinterDialog::on_selection_changed, this);

    m_sizer_printer->Add(m_comboBox_printer, 1, wxEXPAND | wxRIGHT, FromDIP(5));
    // y96
    btn_bg_enable = StateColor(std::pair<wxColour, int>(wxColour(40, 90, 220), StateColor::Pressed), std::pair<wxColour, int>(wxColour(100, 150, 255), StateColor::Hovered),
                               std::pair<wxColour, int>(wxColour(68, 121, 251), StateColor::Normal));

    m_button_refresh = new Button(this, _L("Refresh"));
    m_button_refresh->SetBackgroundColor(btn_bg_enable);
    m_button_refresh->SetBorderColor(btn_bg_enable);
    m_button_refresh->SetTextColor(StateColor::darkModeColorFor("#FFFFFE"));
    m_button_refresh->SetSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE);
    m_button_refresh->SetMinSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE);
    m_button_refresh->SetCornerRadius(FromDIP(10));
    m_button_refresh->Bind(wxEVT_BUTTON, &SendToPrinterDialog::on_refresh, this);
    m_sizer_printer->Add(m_button_refresh, 0, wxALL | wxLEFT, FromDIP(5));

    // y21
    wxPanel* switch_button_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxTAB_TRAVERSAL | wxBU_RIGHT);
    wxBoxSizer* printer_sizer = new wxBoxSizer(wxHORIZONTAL);
    switch_button_panel->SetBackgroundColour(StateColor::darkModeColorFor(wxColour("#FFFFFF")));
    m_switch_button = new SwitchButton(switch_button_panel);
    m_switch_button->SetMaxSize(wxSize(100, 100));
    m_switch_button->SetLabels(_L("Local"), _L("Link"));
    m_switch_button->SetValue(m_isNetMode);
    m_switch_button->Bind(wxEVT_TOGGLEBUTTON, [this](wxCommandEvent& evt) {
        bool is_checked = evt.GetInt();
        m_switch_button->SetValue(is_checked);
        m_isNetMode = is_checked;
        m_comboBox_printer->SetValue("");
        m_comboBox_printer->Clear();
        if (!m_isNetMode)
        {
            for (auto machine : machine_list_local)
            {
                //y24
                m_comboBox_printer->Append(from_u8(machine.display_name));
                if (m_comboBox_printer->GetValue().empty() && preset_typename_normalized.find(NormalizeVendor(machine.type)) != std::string::npos)
                {
                    m_comboBox_printer->SetStringSelection(from_u8(machine.display_name));
                    wxCommandEvent event(wxEVT_COMBOBOX, m_comboBox_printer->GetId());
                    event.SetEventObject(m_comboBox_printer);
                    event.SetString(m_comboBox_printer->GetValue());
                    m_comboBox_printer->GetEventHandler()->ProcessEvent(event);
                }   
            }
        }
        else
        {
#if QDT_RELEASE_TO_PUBLIC
            for (auto machine : machine_list_link)
            {
                //y24
                m_comboBox_printer->Append(from_u8(machine.display_name));
                if (m_comboBox_printer->GetValue().empty() && preset_typename_normalized.find(NormalizeVendor(machine.type)) != std::string::npos)
                {
                    m_comboBox_printer->SetStringSelection(from_u8(machine.display_name));
                    wxCommandEvent event(wxEVT_COMBOBOX, m_comboBox_printer->GetId());
                    event.SetEventObject(m_comboBox_printer);
                    event.SetString(m_comboBox_printer->GetValue());
                    m_comboBox_printer->GetEventHandler()->ProcessEvent(event);
                }
            }
#endif 
        }
        // y27
        if (m_comboBox_printer->GetValue().empty())
        {
            m_button_ensure->Disable();
            m_button_ensure->SetBackgroundColor(wxColour(0x90, 0x90, 0x90));
            m_button_ensure->SetBorderColor(wxColour(0x90, 0x90, 0x90));
        }
    });

    m_isSwitch = new wxCheckBox(switch_button_panel, wxID_ANY, _L("Switch to Device tab"), wxDefaultPosition);
    m_isSwitch->SetValue((wxGetApp().app_config->get("switch to device tab after upload") == "true") ? true : false);
    m_isSwitch->SetForegroundColour(StateColor::darkModeColorFor(wxColour(0, 0, 0)));
    wxToolTip* switch_tips = new wxToolTip(_L("Switch to Device tab after upload."));
    m_isSwitch->SetToolTip(switch_tips);

    printer_sizer->Add(m_switch_button, 0, wxALIGN_CENTER);
    printer_sizer->AddSpacer(20);
    printer_sizer->Add(m_isSwitch, 1, wxALIGN_CENTER);
    switch_button_panel->SetSizer(printer_sizer);
    switch_button_panel->Layout();

    /*select storage*/
    m_storage_panel = new wxPanel(this);
    m_storage_panel->SetBackgroundColour(*wxWHITE);
    m_storage_sizer = new wxBoxSizer(wxHORIZONTAL);
    m_storage_panel->SetSizer(m_storage_sizer);
    m_storage_panel->Layout();

    // try to connect
    m_statictext_printer_msg = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);
    m_statictext_printer_msg->SetFont(::Label::Body_13);
    m_statictext_printer_msg->SetForegroundColour(*wxBLACK);
    m_statictext_printer_msg->Hide();

    wxBoxSizer *m_sizer_connecting      = new wxBoxSizer(wxHORIZONTAL);
    m_connecting_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);

    m_connecting_printer_msg = new wxStaticText(m_connecting_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);
    m_connecting_printer_msg->SetFont(::Label::Body_13);
    m_connecting_printer_msg->SetForegroundColour(*wxBLACK);
    m_connecting_printer_msg->SetLabel(_L("Try to connect"));
    /*m_connecting_printer_msg->Hide();*/
    m_connecting_printer_msg->Show();

    std::vector<std::string> list{"ams_rfid_1", "ams_rfid_2", "ams_rfid_3", "ams_rfid_4"};
    m_animaicon = new AnimaIcon(m_connecting_panel, wxID_ANY, list, "refresh_printer", 100);
    m_sizer_connecting->Add(m_connecting_printer_msg, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(5));
    m_sizer_connecting->Add(m_animaicon, 0, wxALIGN_CENTER_VERTICAL);

    m_connecting_panel->SetSizer(m_sizer_connecting);
    m_connecting_panel->Layout();
    m_connecting_panel->Fit();
    m_connecting_panel->Hide();

    m_animaicon->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) {
        if (m_file_sys) {
            /* static int i = 0;
             i++;
             OutputDebugStringA(std::to_string(i).c_str());
             OutputDebugStringA("\n");*/
            m_file_sys->Retry();
            wxLogMessage(_L("click to retry"));
        }
    });

    // line schedule
    m_line_schedule = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1));
    m_line_schedule->SetBackgroundColour(wxColour(238, 238, 238));
    m_simplebook   = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, SELECT_MACHINE_DIALOG_SIMBOOK_SIZE, 0);

    // perpare mode
    m_panel_prepare = new wxPanel(m_simplebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
    m_panel_prepare->SetBackgroundColour(m_colour_def_color);
    // m_panel_prepare->SetBackgroundColour(wxColour(135,206,250));
    wxBoxSizer *m_sizer_prepare = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer *m_sizer_pcont   = new wxBoxSizer(wxHORIZONTAL);

    m_sizer_prepare->Add(0, 0, 1, wxTOP, FromDIP(22));

    auto hyperlink_sizer = new wxBoxSizer(wxHORIZONTAL);
    //y36
    std::string language = wxGetApp().app_config->get("language");
    wxString    region    = L"en";
    if (language.find("zh") == 0)
        region = L"zh";
    wxString hyperlink_2 = wxString::Format(L"https://wiki.qidi3d.com/%s/software/qidi-studio/troubleshooting/connect-send-problem", region);
    m_hyperlink = new wxHyperlinkCtrl(m_panel_prepare, wxID_ANY, _L("Click here if you failed to send the print job"), hyperlink_2, wxDefaultPosition, wxDefaultSize, wxHL_DEFAULT_STYLE);

    hyperlink_sizer->Add(m_hyperlink, 0, wxALIGN_CENTER | wxALL, 5);
    m_sizer_prepare->Add(hyperlink_sizer, 0, wxALIGN_CENTER | wxALL, 5);

    m_button_ensure = new Button(m_panel_prepare, _L("Send"));
    m_button_ensure->SetBackgroundColor(btn_bg_enable);
    m_button_ensure->SetBorderColor(btn_bg_enable);
    m_button_ensure->SetTextColor(StateColor::darkModeColorFor("#FFFFFE"));
    m_button_ensure->SetSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE);
    m_button_ensure->SetMinSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE);
    m_button_ensure->SetCornerRadius(12);

    m_button_ensure->Bind(wxEVT_BUTTON, &SendToPrinterDialog::on_ok, this);
    m_sizer_pcont->Add(0, 0, 1, wxEXPAND, 0);
    m_sizer_pcont->Add(m_button_ensure, 0, wxRIGHT, 0);
    m_sizer_prepare->Add(m_sizer_pcont, 0, wxEXPAND, 0);
    m_panel_prepare->SetSizer(m_sizer_prepare);
    m_panel_prepare->Layout();
    m_simplebook->AddPage(m_panel_prepare, wxEmptyString, true);

    // sending mode
    m_status_bar    = std::make_shared<QDTStatusBarSend>(m_simplebook);
    m_panel_sending = m_status_bar->get_panel();
    m_simplebook->AddPage(m_panel_sending, wxEmptyString, false);

    // finish mode
    m_panel_finish = new wxPanel(m_simplebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
    m_panel_finish->SetBackgroundColour(wxColour(135, 206, 250));
    wxBoxSizer *m_sizer_finish   = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer *m_sizer_finish_v = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer *m_sizer_finish_h = new wxBoxSizer(wxHORIZONTAL);

    auto imgsize      = FromDIP(25);
    auto completedimg = new wxStaticBitmap(m_panel_finish, wxID_ANY, create_scaled_bitmap("completed", m_panel_finish, 25), wxDefaultPosition, wxSize(imgsize, imgsize), 0);
    m_sizer_finish_h->Add(completedimg, 0, wxALIGN_CENTER | wxALL, FromDIP(5));

    m_statictext_finish = new wxStaticText(m_panel_finish, wxID_ANY, L("send completed"), wxDefaultPosition, wxDefaultSize, 0);
    m_statictext_finish->Wrap(-1);
    // y96
    m_statictext_finish->SetForegroundColour(wxColour(68, 121, 251));
    m_sizer_finish_h->Add(m_statictext_finish, 0, wxALIGN_CENTER | wxALL, FromDIP(5));

    m_sizer_finish_v->Add(m_sizer_finish_h, 1, wxALIGN_CENTER, 0);

    m_sizer_finish->Add(m_sizer_finish_v, 1, wxALIGN_CENTER, 0);

    m_panel_finish->SetSizer(m_sizer_finish);
    m_panel_finish->Layout();
    m_sizer_finish->Fit(m_panel_finish);
    m_simplebook->AddPage(m_panel_finish, wxEmptyString, false);

    //show bind failed info
    m_sw_print_failed_info = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(380), FromDIP(125)), wxVSCROLL);
    m_sw_print_failed_info->SetBackgroundColour(*wxWHITE);
    m_sw_print_failed_info->SetScrollRate(0, 5);
    m_sw_print_failed_info->SetMinSize(wxSize(FromDIP(380), FromDIP(125)));
    m_sw_print_failed_info->SetMaxSize(wxSize(FromDIP(380), FromDIP(125)));

    wxBoxSizer* sizer_print_failed_info = new wxBoxSizer(wxVERTICAL);
    m_sw_print_failed_info->SetSizer(sizer_print_failed_info);


    wxBoxSizer* sizer_error_code = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* sizer_error_desc = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* sizer_extra_info = new wxBoxSizer(wxHORIZONTAL);

    auto st_title_error_code = new wxStaticText(m_sw_print_failed_info, wxID_ANY, _L("Error code"));
    auto st_title_error_code_doc = new wxStaticText(m_sw_print_failed_info, wxID_ANY, ": ");
    m_st_txt_error_code = new Label(m_sw_print_failed_info, wxEmptyString);
    st_title_error_code->SetForegroundColour(0x909090);
    st_title_error_code_doc->SetForegroundColour(0x909090);
    m_st_txt_error_code->SetForegroundColour(0x909090);
    st_title_error_code->SetFont(::Label::Body_13);
    st_title_error_code_doc->SetFont(::Label::Body_13);
    m_st_txt_error_code->SetFont(::Label::Body_13);
    st_title_error_code->SetMinSize(wxSize(FromDIP(74), -1));
    st_title_error_code->SetMaxSize(wxSize(FromDIP(74), -1));
    m_st_txt_error_code->SetMinSize(wxSize(FromDIP(260), -1));
    m_st_txt_error_code->SetMaxSize(wxSize(FromDIP(260), -1));
    sizer_error_code->Add(st_title_error_code, 0, wxALL, 0);
    sizer_error_code->Add(st_title_error_code_doc, 0, wxALL, 0);
    sizer_error_code->Add(m_st_txt_error_code, 0, wxALL, 0);


    auto st_title_error_desc = new wxStaticText(m_sw_print_failed_info, wxID_ANY, wxT("Error desc"));
    auto st_title_error_desc_doc = new wxStaticText(m_sw_print_failed_info, wxID_ANY, ": ");
    m_st_txt_error_desc = new Label(m_sw_print_failed_info, wxEmptyString);
    st_title_error_desc->SetForegroundColour(0x909090);
    st_title_error_desc_doc->SetForegroundColour(0x909090);
    m_st_txt_error_desc->SetForegroundColour(0x909090);
    st_title_error_desc->SetFont(::Label::Body_13);
    st_title_error_desc_doc->SetFont(::Label::Body_13);
    m_st_txt_error_desc->SetFont(::Label::Body_13);
    st_title_error_desc->SetMinSize(wxSize(FromDIP(74), -1));
    st_title_error_desc->SetMaxSize(wxSize(FromDIP(74), -1));
    m_st_txt_error_desc->SetMinSize(wxSize(FromDIP(260), -1));
    m_st_txt_error_desc->SetMaxSize(wxSize(FromDIP(260), -1));
    sizer_error_desc->Add(st_title_error_desc, 0, wxALL, 0);
    sizer_error_desc->Add(st_title_error_desc_doc, 0, wxALL, 0);
    sizer_error_desc->Add(m_st_txt_error_desc, 0, wxALL, 0);

    auto st_title_extra_info = new wxStaticText(m_sw_print_failed_info, wxID_ANY, wxT("Extra info"));
    auto st_title_extra_info_doc = new wxStaticText(m_sw_print_failed_info, wxID_ANY, ": ");
    m_st_txt_extra_info = new Label(m_sw_print_failed_info, wxEmptyString);
    st_title_extra_info->SetForegroundColour(0x909090);
    st_title_extra_info_doc->SetForegroundColour(0x909090);
    m_st_txt_extra_info->SetForegroundColour(0x909090);
    st_title_extra_info->SetFont(::Label::Body_13);
    st_title_extra_info_doc->SetFont(::Label::Body_13);
    m_st_txt_extra_info->SetFont(::Label::Body_13);
    st_title_extra_info->SetMinSize(wxSize(FromDIP(74), -1));
    st_title_extra_info->SetMaxSize(wxSize(FromDIP(74), -1));
    m_st_txt_extra_info->SetMinSize(wxSize(FromDIP(260), -1));
    m_st_txt_extra_info->SetMaxSize(wxSize(FromDIP(260), -1));
    sizer_extra_info->Add(st_title_extra_info, 0, wxALL, 0);
    sizer_extra_info->Add(st_title_extra_info_doc, 0, wxALL, 0);
    sizer_extra_info->Add(m_st_txt_extra_info, 0, wxALL, 0);


    m_link_network_state = new wxHyperlinkCtrl(m_sw_print_failed_info, wxID_ANY,_L("Check the status of current system services"),"");
    m_link_network_state->SetFont(::Label::Body_12);
    m_link_network_state->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {wxGetApp().link_to_network_check(); });
    m_link_network_state->Bind(wxEVT_ENTER_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_HAND); });
    m_link_network_state->Bind(wxEVT_LEAVE_WINDOW, [this](auto& e) {m_link_network_state->SetCursor(wxCURSOR_ARROW); });

    sizer_print_failed_info->Add(m_link_network_state, 0, wxLEFT, 5);
    sizer_print_failed_info->Add(sizer_error_code, 0, wxLEFT, 5);
    sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3));
    sizer_print_failed_info->Add(sizer_error_desc, 0, wxLEFT, 5);
    sizer_print_failed_info->Add(0, 0, 0, wxTOP, FromDIP(3));
    sizer_print_failed_info->Add(sizer_extra_info, 0, wxLEFT, 5);

    // bind
    Bind(EVT_SHOW_ERROR_INFO_SEND, [this](auto& e) {
        show_print_failed_info(true);
    });

    // bind
    Bind(EVT_UPDATE_USER_MACHINE_LIST, &SendToPrinterDialog::update_printer_combobox, this);
    Bind(EVT_PRINT_JOB_CANCEL, &SendToPrinterDialog::on_print_job_cancel, this);


    m_sizer_scrollable_region->Add(m_panel_image, 0, wxALIGN_CENTER_HORIZONTAL, 0);
    m_sizer_scrollable_region->Add(0, 0, 0, wxTOP, FromDIP(10));
    m_sizer_scrollable_region->Add(m_sizer_basic, 0, wxALIGN_CENTER_HORIZONTAL, 0);
	m_scrollable_region->SetSizer(m_sizer_scrollable_region);
	m_scrollable_region->Layout();

    //file name
    //rename normal
    m_rename_switch_panel = new wxSimplebook(this);
    m_rename_switch_panel->SetSize(wxSize(FromDIP(420), FromDIP(25)));
    m_rename_switch_panel->SetMinSize(wxSize(FromDIP(420), FromDIP(25)));
    m_rename_switch_panel->SetMaxSize(wxSize(FromDIP(420), FromDIP(25)));

    m_rename_normal_panel = new wxPanel(m_rename_switch_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
    m_rename_normal_panel->SetBackgroundColour(*wxWHITE);
    rename_sizer_v = new wxBoxSizer(wxVERTICAL);
    rename_sizer_h = new wxBoxSizer(wxHORIZONTAL);

    m_rename_text = new wxStaticText(m_rename_normal_panel, wxID_ANY, wxT("MyLabel"), wxDefaultPosition, wxDefaultSize, wxST_ELLIPSIZE_END);
    m_rename_text->SetForegroundColour(*wxBLACK);
    m_rename_text->SetFont(::Label::Body_13);
    m_rename_text->SetMaxSize(wxSize(FromDIP(390), -1));
    m_rename_button = new Button(m_rename_normal_panel, "", "ams_editable", wxBORDER_NONE, FromDIP(10));
    m_rename_button->SetBackgroundColor(*wxWHITE);
    m_rename_button->SetBackgroundColour(*wxWHITE);

    rename_sizer_h->Add(m_rename_text, 0, wxALIGN_CENTER, 0);
    rename_sizer_h->Add(m_rename_button, 0, wxALIGN_CENTER, 0);
    rename_sizer_v->Add(rename_sizer_h, 1, wxALIGN_CENTER, 0);
    m_rename_normal_panel->SetSizer(rename_sizer_v);
    m_rename_normal_panel->Layout();
    rename_sizer_v->Fit(m_rename_normal_panel);

    //rename edit
    auto m_rename_edit_panel = new wxPanel(m_rename_switch_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
    m_rename_edit_panel->SetBackgroundColour(*wxWHITE);
    auto rename_edit_sizer_v = new wxBoxSizer(wxVERTICAL);

    m_rename_input = new ::TextInput(m_rename_edit_panel, wxEmptyString, wxEmptyString, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
    m_rename_input->GetTextCtrl()->SetFont(::Label::Body_13);
    m_rename_input->SetSize(wxSize(FromDIP(380), FromDIP(24)));
    m_rename_input->SetMinSize(wxSize(FromDIP(380), FromDIP(24)));
    m_rename_input->SetMaxSize(wxSize(FromDIP(380), FromDIP(24)));
    m_rename_input->Bind(wxEVT_TEXT_ENTER, [this](auto& e) {on_rename_enter();});
    m_rename_input->Bind(wxEVT_KILL_FOCUS, [this](auto& e) {
        if (!m_rename_input->HasFocus() && !m_rename_text->HasFocus())
            on_rename_enter();
        else
            e.Skip(); });
    rename_edit_sizer_v->Add(m_rename_input, 1, wxALIGN_CENTER, 0);


    m_rename_edit_panel->SetSizer(rename_edit_sizer_v);
    m_rename_edit_panel->Layout();
    rename_edit_sizer_v->Fit(m_rename_edit_panel);

    m_rename_button->Bind(wxEVT_BUTTON, &SendToPrinterDialog::on_rename_click, this);
    m_rename_switch_panel->AddPage(m_rename_normal_panel, wxEmptyString, true);
    m_rename_switch_panel->AddPage(m_rename_edit_panel, wxEmptyString, false);

    Bind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& e) {
        if (e.GetKeyCode() == WXK_ESCAPE) {
            if (m_rename_switch_panel->GetSelection() == 0) {
                e.Skip();
            }
            else {
                m_rename_switch_panel->SetSelection(0);
                m_rename_text->SetLabel(m_current_project_name);
                m_rename_normal_panel->Layout();
            }
        }
        else {
            e.Skip();
        }
        });

    m_panel_prepare->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
        check_fcous_state(this);
        e.Skip();
        });

    m_scrollable_region->Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
        check_fcous_state(this);
        e.Skip();
        });

    Bind(wxEVT_LEFT_DOWN, [this](auto& e) {
        check_fcous_state(this);
        e.Skip();
        });

    m_sizer_main->Add(m_line_top, 0, wxEXPAND, 0);
    m_sizer_main->Add(0, 0, 0, wxTOP, FromDIP(10));
    m_sizer_main->Add(m_scrollable_region, 0, wxALIGN_CENTER_HORIZONTAL, 0);
    m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(6));
    m_sizer_main->Add(m_rename_switch_panel, 0, wxALIGN_CENTER_HORIZONTAL, 0);
    m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(6));
    m_sizer_main->Add(m_line_materia, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));
    m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(12));
    m_sizer_main->Add(switch_button_panel, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));
    m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(12));
    m_sizer_main->Add(m_sizer_printer, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));
    m_sizer_main->Add(m_storage_panel, 0, wxALIGN_CENTER | wxTOP, FromDIP(8));
    m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(11));
    m_sizer_main->Add(m_statictext_printer_msg, 0, wxALIGN_CENTER_HORIZONTAL, 0);
    m_sizer_main->Add(m_connecting_panel, 0, wxALIGN_CENTER_HORIZONTAL, 0);
    m_sizer_main->Add(0, 1, 0, wxTOP, FromDIP(10));
    m_sizer_main->Add(m_line_schedule, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));
    m_sizer_main->Add(m_simplebook, 0, wxALIGN_CENTER_HORIZONTAL, 0);
    m_sizer_main->Add(m_sw_print_failed_info, 0, wxALIGN_CENTER, 0);
    m_sizer_main->Add(0, 0, 0, wxEXPAND | wxTOP, FromDIP(13));

    show_print_failed_info(false);
    //y58
    update_user_printer();
    SetSizer(m_sizer_main);
    Layout();
    Fit();
    Thaw();

    init_bind();
    init_timer();
    // CenterOnParent();
    Centre(wxBOTH);
    wxGetApp().UpdateDlgDarkUI(this);
}

std::string SendToPrinterDialog::get_storage_selected()
{
    for (const auto& radio : m_storage_radioBox) {
        if (radio->GetValue()) {
            return radio->GetLabel().ToStdString();
        }
    }
    return "";
}

void SendToPrinterDialog::update_storage_list(const std::vector<std::string>& storages)
{
    m_storage_sizer->Clear();
    m_storage_radioBox.clear();
    m_storage_panel->DestroyChildren();

    for (int i=0; i < storages.size(); i++) {
        if (storages[i] == EMMC_STORAGE) continue;
        RadioBox* radiobox = new RadioBox(m_storage_panel);
        Label* storage_text = new Label(m_storage_panel, storages[i]);
        radiobox->SetLabel(storages[i]);
        radiobox->Bind(wxEVT_LEFT_DOWN, [this, radiobox](auto& e) {
            for (const auto& radio : m_storage_radioBox) {
                radio->SetValue(false);
            }
            radiobox->SetValue(true);
        });

        m_storage_sizer->Add(radiobox, 0, wxALIGN_CENTER, 0);
        m_storage_sizer->Add(0, 0, 0, wxEXPAND|wxLEFT, FromDIP(6));
        m_storage_sizer->Add(storage_text, 0, wxALIGN_CENTER,0);
        m_storage_radioBox.push_back(radiobox);
    }

    if (m_storage_radioBox.size() > 0) {
        m_storage_sizer->Add(0, 0, 0, wxEXPAND, FromDIP(6));
        auto radio = m_storage_radioBox.front();
        radio->SetValue(true);
    }

    m_storage_panel->Layout();
    m_storage_panel->Fit();
    Layout();
    Fit();
}
void SendToPrinterDialog::update_print_error_info(int code, std::string msg, std::string extra)
{
    m_print_error_code = code;
    m_print_error_msg = msg;
    m_print_error_extra = extra;
}

void SendToPrinterDialog::show_print_failed_info(bool show, int code, wxString description, wxString extra)
{
    if (show) {
        if (!m_sw_print_failed_info->IsShown()) {
            m_sw_print_failed_info->Show(true);

            m_st_txt_error_code->SetLabelText(wxString::Format("%d", m_print_error_code));
            m_st_txt_error_desc->SetLabelText( wxGetApp().filter_string(m_print_error_msg));
            m_st_txt_extra_info->SetLabelText( wxGetApp().filter_string(m_print_error_extra));

            m_st_txt_error_code->Wrap(FromDIP(260));
            m_st_txt_error_desc->Wrap(FromDIP(260));
            m_st_txt_extra_info->Wrap(FromDIP(260));
        }
        else {
            m_sw_print_failed_info->Show(false);
        }
        Layout();
        Fit();
    }
    else {
        if (!m_sw_print_failed_info->IsShown()) { return; }
        m_sw_print_failed_info->Show(false);
        m_st_txt_error_code->SetLabelText(wxEmptyString);
        m_st_txt_error_desc->SetLabelText(wxEmptyString);
        m_st_txt_extra_info->SetLabelText(wxEmptyString);
        Layout();
        Fit();
    }
}

void SendToPrinterDialog::prepare_mode()
{
    m_is_in_sending_mode = false;
    m_comboBox_printer->Enable();
    if (m_send_job) {
        m_send_job->join();
    }

    if (wxIsBusy())
        wxEndBusyCursor();
    Enable_Send_Button(true);
    show_print_failed_info(false);

    m_status_bar->reset();
    if (m_simplebook->GetSelection() != 0) {
        m_simplebook->SetSelection(0);
    }
}

void SendToPrinterDialog::sending_mode()
{
    m_is_in_sending_mode = true;
    m_comboBox_printer->Disable();
    if (m_simplebook->GetSelection() != 1){
        m_simplebook->SetSelection(1);
        Layout();
        Fit();
    }
}

void SendToPrinterDialog::prepare(int print_plate_idx)
{
    m_print_plate_idx = print_plate_idx;
}

void SendToPrinterDialog::update_priner_status_msg(wxString msg, bool is_warning)
{
    auto colour = is_warning ? wxColour(0xFF, 0x6F, 0x00) : wxColour(0x6B, 0x6B, 0x6B);
    m_statictext_printer_msg->SetForegroundColour(colour);

    if (msg.empty()) {
        if (!m_statictext_printer_msg->GetLabel().empty()) {
            m_statictext_printer_msg->SetLabel(wxEmptyString);
            m_statictext_printer_msg->Hide();
            Layout();
            Fit();
        }
    } else {
        msg          = format_text(msg);

        auto str_new = msg.ToStdString();
        stripWhiteSpace(str_new);

        auto str_old = m_statictext_printer_msg->GetLabel().ToStdString();
        stripWhiteSpace(str_old);

        if (str_new != str_old) {
            if (m_statictext_printer_msg->GetLabel() != msg) {
                m_statictext_printer_msg->SetLabel(msg);
                m_statictext_printer_msg->SetMinSize(wxSize(FromDIP(400), -1));
                m_statictext_printer_msg->SetMaxSize(wxSize(FromDIP(400), -1));
                m_statictext_printer_msg->Wrap(FromDIP(400));
                m_statictext_printer_msg->Show();
                Layout();
                Fit();
            }
        }
    }
}

void SendToPrinterDialog::update_print_status_msg(wxString msg, bool is_warning, bool is_printer_msg)
{
    if (is_printer_msg) {
        update_priner_status_msg(msg, is_warning);
    } else {
        update_priner_status_msg(wxEmptyString, false);
    }
}


void SendToPrinterDialog::init_bind()
{
    Bind(wxEVT_TIMER, &SendToPrinterDialog::on_timer, this);
    Bind(EVT_CLEAR_IPADDRESS, &SendToPrinterDialog::clear_ip_address_config, this);
}

void SendToPrinterDialog::init_timer()
{
    m_refresh_timer = new wxTimer();
    m_refresh_timer->SetOwner(this);
}

void SendToPrinterDialog::on_cancel(wxCloseEvent &event)
{
    if (m_send_job) {
        if (m_send_job->is_running()) {
            m_send_job->cancel();
            m_send_job->join();
        }
    }

    if (m_file_sys) {
        m_file_sys->CancelUploadTask();

        if (m_task_timer && m_task_timer->IsRunning()) {
            m_task_timer->Stop();
            m_task_timer.reset();
        }
        m_file_sys->Stop(true);
        m_file_sys.reset();
    }
    m_tcp_try_connect = true;
    m_tutk_try_connect = false;
    m_ftp_try_connect  = false;
    m_connect_try_times = 0;

    this->EndModal(wxID_CANCEL);
}

void SendToPrinterDialog::on_ok(wxCommandEvent &event)
{
    bool isSwitch = m_isSwitch->GetValue();
    if (isSwitch)
        wxGetApp().app_config->set_bool("switch to device tab after upload", true);
    else
        wxGetApp().app_config->set_bool("switch to device tab after upload", false);

    // y16
    machine_name = into_u8(m_comboBox_printer->GetValue());

    //y24
    if (!m_isNetMode)
    {
        for (auto machine : machine_list_local)
        {
            if (machine.display_name == machine_name)
            {
                machine_url = machine.url;
                machine_ip = machine.ip;
                machine_apikey = machine.apikey;
                break;
            }
        }
    }
    else
    {
#if QDT_RELEASE_TO_PUBLIC
        for (auto machine : machine_list_link)
        {
            if (machine.display_name == machine_name)
            {
                machine_url = machine.url;
                machine_ip = machine.ip;
                machine_apikey = "";
                machine_link_url = machine.link_url;
                machine_is_special = machine.is_special;
                break;
            }
        }
#endif 
    }

    //y58
    bool qidi_3mf = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt_bool("is_support_3mf");

    Enable_Send_Button(false);
    m_is_canceled = false;
    fs::path output_path(m_plater->model().get_backup_path());
    show_status(PrintDialogStatus::PrintStatusSending);
    output_path += "/temp_file";
    std::string upload_file_name = into_u8(m_current_project_name);

    m_status_bar->reset();
    m_status_bar->set_prog_block();
    m_status_bar->set_cancel_callback_fina([this]() {
        m_is_canceled = true;
        wxCommandEvent* event = new wxCommandEvent(EVT_PRINT_JOB_CANCEL);
        wxQueueEvent(this, event);
        });
    
    if (m_is_canceled) {
        BOOST_LOG_TRIVIAL(info) << "send_job: m_is_canceled";
        //m_status_bar->set_status_text(task_canceled_text);
        return;
    }
    sending_mode();

    wxString msg = _L("Preparing print job");
    m_status_bar->update_status(msg, m_is_canceled, 0, true);

    if (qidi_3mf) {
        if (boost::iends_with(output_path.string(), ".gcode")) {
            std::wstring temp_path = output_path.wstring();
            temp_path = temp_path.substr(0, temp_path.size() - 6);
            output_path = temp_path + L".gcode.3mf";
        }
        else if (boost::iends_with(output_path.string(), ".gcode.gcode.3mf")) {//for mac
            std::wstring temp_path = output_path.wstring();
            temp_path = temp_path.substr(0, temp_path.size() - 16);
            output_path = temp_path + L".gcode.3mf";
        }
        else if (!boost::iends_with(output_path.string(), ".gcode.3mf")) {
            output_path = output_path.replace_extension(".gcode.3mf");
        }
        upload_file_name += ".gcode.3mf";
        int result = m_plater->export_3mf(output_path, SaveStrategy::Silence | SaveStrategy::SplitModel | SaveStrategy::WithGcode | SaveStrategy::SkipModel, m_print_plate_idx);
    }
    else {
        if (!boost::iends_with(output_path.string(), ".gcode"))
        {
            output_path += ".gcode";
        }
        upload_file_name += ".gcode";
        m_plater->export_gcode(output_path);
    }

    if (m_isNetMode)
    {
        PrintHostJob upload_job(machine_url, machine_ip);
        upload_job.upload_data.upload_path = upload_file_name;
        upload_job.upload_data.post_action = PrintHostPostUploadAction::None;
        upload_job.upload_data.source_path = output_path.string();
        upload_job.upload_data.is_3mf = qidi_3mf;
        start_to_send(std::move(upload_job));
    }
    else
    {
        DynamicPrintConfig cfg_t;
        cfg_t.set_key_value("print_host", new ConfigOptionString(machine_url));
        cfg_t.set_key_value("host_type", new ConfigOptionString("ptfff"));
        cfg_t.set_key_value("printhost_apikey", new ConfigOptionString(machine_apikey));
        PrintHostJob upload_job(&cfg_t);
        upload_job.upload_data.upload_path = upload_file_name;
        upload_job.upload_data.post_action = PrintHostPostUploadAction::None;
        upload_job.upload_data.source_path = output_path.string();
        upload_job.upload_data.is_3mf = qidi_3mf;
        start_to_send(std::move(upload_job));
    }
    // BOOST_LOG_TRIVIAL(info) << "print_job: on_ok to send !";
//     m_is_canceled = false;
//     Enable_Send_Button(false);
//     if (m_is_in_sending_mode)
//         return;

//     int result = 0;
//     if (m_printer_last_select.empty()) {
//         return;
//     }

//     DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager();
//     if (!dev) return;

//     MachineObject *obj_ = dev->get_selected_machine();

//     if (obj_ == nullptr) {
//         m_printer_last_select = "";
//         m_comboBox_printer->SetTextLabel("");
//         return;
//     }
//     assert(obj_->dev_id == m_printer_last_select);


//     BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", print_job: for send task, current printer id =  " <<  QDTCrossTalk::Crosstalk_DevId(m_printer_last_select) << std::endl;
//     show_status(PrintDialogStatus::PrintStatusSending);

//     m_status_bar->reset();
//     m_status_bar->set_prog_block();
//     m_status_bar->set_cancel_callback_fina([this]() {
//         BOOST_LOG_TRIVIAL(info) << "print_job: enter canceled";
//         if (m_send_job) {
//             if (m_send_job->is_running()) {
//                 BOOST_LOG_TRIVIAL(info) << "send_job: canceled";
//                 m_send_job->cancel();
//             }
//             m_send_job->join();
//         }

//         if (m_file_sys) {
//             m_file_sys->CancelUploadTask();
//             if (m_task_timer && m_task_timer->IsRunning()) {
//                 m_task_timer->Stop();
//                 m_task_timer.reset();
//             }
//         }

//         m_is_canceled = true;
//         wxCommandEvent* event = new wxCommandEvent(EVT_PRINT_JOB_CANCEL);
//         wxQueueEvent(this, event);
//     });

//     if (m_is_canceled) {
//         BOOST_LOG_TRIVIAL(info) << "send_job: m_is_canceled";
//         //m_status_bar->set_status_text(task_canceled_text);
//         return;
//     }

//     // enter sending mode
//     sending_mode();

    // if (wxGetApp().plater()->using_exported_file()) {
    //     m_plater->set_print_job_plate_idx(m_print_plate_idx);
    //     result = 0;
    // }
    //  else {
    //      result = m_plater->send_gcode(m_print_plate_idx, [this](int export_stage, int current, int total, bool &cancel) {
    //          if (this->m_is_canceled) return;
    //          bool     cancelled = false;
    //          wxString msg       = _L("Preparing print job");
    //          m_status_bar->update_status(msg, cancelled, 10, true);
    //          m_export_3mf_cancel = cancel = cancelled;
    //      });
    //  }

//     if (m_is_canceled || m_export_3mf_cancel) {
//         BOOST_LOG_TRIVIAL(info) << "send_job: m_export_3mf_cancel or m_is_canceled";
//         //m_status_bar->set_status_text(task_canceled_text);
//         return;
//     }

//     if (result < 0) {
//         wxString msg = _L("Abnormal print file data. Please slice again");
//         m_status_bar->set_status_text(msg);
//         return;
//     }

//     // export config 3mf if needed
    // if(!wxGetApp().plater()->using_exported_file() && !obj_->is_lan_mode_printer()) {
    //         result = m_plater->export_config_3mf(m_print_plate_idx);
    //         if (result < 0) {
    //             BOOST_LOG_TRIVIAL(info) << "export_config_3mf failed, result = " << result;
    //             return;
    //         }
//         }

//     if (m_is_canceled || m_export_3mf_cancel) {
//         BOOST_LOG_TRIVIAL(info) << "send_job: m_export_3mf_cancel or m_is_canceled";
//         //m_status_bar->set_status_text(task_canceled_text);
//         return;
//     }

//    /* std::string  file_name       = "";
// 	auto default_output_file    = wxGetApp().plater()->get_export_gcode_filename(".3mf");
//     if (!default_output_file.empty()) {
// 		fs::path default_output_file_path = boost::filesystem::path(default_output_file.c_str());
// 		file_name = default_output_file_path.filename().string();
//     }*/

    // if (obj_->is_support_brtc && (m_tcp_try_connect || m_tutk_try_connect))
    // {
//         update_print_status_msg(wxEmptyString, false, false);
//         if (m_file_sys) {
//             PrintPrepareData print_data;
//             m_plater->get_print_job_data(&print_data);
//             std::string project_name = m_current_project_name.utf8_string() + ".gcode.3mf";

            // std::string _3mf_path;
            // if (wxGetApp().plater()->using_exported_file())
            //     _3mf_path = wxGetApp().plater()->get_3mf_filename();
            // else
            //      _3mf_path = print_data._3mf_path.string();
//             auto it = std::find_if(m_ability_list.begin(), m_ability_list.end(), [](const std::string& s) {
//                 return s != EMMC_STORAGE;
//             });

//             if (it != m_ability_list.end())
//                 m_file_sys->SetUploadFile(_3mf_path, project_name, *it);
                // m_file_sys->RequestUploadFile();

                // // time out
                // if (m_task_timer && m_task_timer->IsRunning()) m_task_timer->Stop();

                // m_task_timer.reset(new wxTimer());
                // m_task_timer->SetOwner(this);

            //     this->Bind(
            //         wxEVT_TIMER,
            //         [this, wfs = boost::weak_ptr(m_file_sys), obj_](auto e) {
            //             show_status(PrintDialogStatus::PrintStatusPublicUploadFiled);
            //             boost::shared_ptr fs(wfs.lock());
            //             if (!fs) return;
            //             fs->CancelUploadTask(false);

            //            //first time use tcp, second time use tutk , secnod time use ftp
            //             if (m_connect_try_times < 2) {
            //                 bool is_lan = (obj_->connection_type() == "lan");
            //                 m_tcp_try_connect = false;

            //                 if (is_lan) {
            //                     m_ftp_try_connect  = true;
            //                     m_tutk_try_connect = false;
            //                 } else {
            //                     if (m_connect_try_times == 0) {
            //                         m_ftp_try_connect  = false;
            //                         m_tutk_try_connect = true;
            //                     } else {
            //                         m_ftp_try_connect  = true;
            //                         m_tutk_try_connect = false;
            //                     }
            //                 }
            //                 BOOST_LOG_TRIVIAL(info) << "send  failed";
            //                 BOOST_LOG_TRIVIAL(info) << "m_ftp_try_connect is  " << m_ftp_try_connect ;
            //                 BOOST_LOG_TRIVIAL(info) << "m_tutk_try_connect is  " << m_tutk_try_connect ;
            //                 BOOST_LOG_TRIVIAL(info) << "m_tcp_try_connect is  " << m_tcp_try_connect ;
            //             } else
            //                 update_print_status_msg(_L("Upload file timeout, please check if the firmware version supports it."), false, true);
            //             m_connect_try_times++;
            //         },
            //         m_task_timer->GetId());
            //         m_task_timer->StartOnce(timeout_period);
            // }
            // else {
            //     BOOST_LOG_TRIVIAL(error) << "SendToPrinter::send job: The printer media capability set is incorrect.";
            //     show_status(PrintDialogStatus::PrintStatusPublicUploadFiled);
            //     update_print_status_msg(_L("No available external storage was obtained. Please confirm and try again."), true, true);
            // }
//         }
//     } else {

//         m_send_job                = std::make_shared<SendJob>(m_status_bar, m_plater, m_printer_last_select);
//         m_send_job->m_dev_ip      = obj_->dev_ip;
//         m_send_job->m_access_code = obj_->get_access_code();

// #if !QDT_RELEASE_TO_PUBLIC
//         m_send_job->m_local_use_ssl_for_ftp  = wxGetApp().app_config->get("enable_ssl_for_ftp") == "true" ? true : false;
//         m_send_job->m_local_use_ssl_for_mqtt = wxGetApp().app_config->get("enable_ssl_for_mqtt") == "true" ? true : false;
// #else
//         m_send_job->m_local_use_ssl_for_ftp  = obj_->local_use_ssl_for_ftp;
//         m_send_job->m_local_use_ssl_for_mqtt = obj_->local_use_ssl_for_mqtt;

// #endif
//         m_send_job->connection_type     = obj_->connection_type();
//         m_send_job->cloud_print_only    = true;
//         m_send_job->has_sdcard          = obj_->get_sdcard_state() == MachineObject::SdcardState::HAS_SDCARD_NORMAL;
//         m_send_job->set_project_name(m_current_project_name.utf8_string());

//         enable_prepare_mode = false;

//         m_send_job->on_check_ip_address_fail([this, token = std::weak_ptr(m_token)](int result) {
//              CallAfter([token, this] {
//                 if (token.expired()) { return; }
//                 if (this) {
//                     SendFailedConfirm sfcDlg;
//                     auto res = sfcDlg.ShowModal();
//                     m_status_bar->cancel();

//                     if (res == wxYES) {
//                         wxQueueEvent(m_button_ensure, new wxCommandEvent(wxEVT_BUTTON));
//                     } else if (res == wxAPPLY) {
//                         wxCommandEvent *evt = new wxCommandEvent(EVT_CLEAR_IPADDRESS);
//                         wxQueueEvent(this, evt);
//                         wxGetApp().show_ip_address_enter_dialog();
//                     }
//                 }
//             });
//         });

//         if (obj_->is_lan_mode_printer()) {
//             m_send_job->set_check_mode();
//             m_send_job->check_and_continue();
//             m_send_job->start();
//         } else {
//             m_send_job->start();
//         }

//     }


    BOOST_LOG_TRIVIAL(info) << "send_job: send print job";
}

//y58
void SendToPrinterDialog::start_to_send(PrintHostJob upload_job) {

    bool success = upload_job.printhost->upload(std::move(upload_job.upload_data),
        [this](Http::Progress progress, bool& cancel) {
            cancel = m_is_canceled;
            int gui_progress = progress.ultotal > 0 ? 100 * progress.ulnow / progress.ultotal : 0;
            OctoPrint::progress_percentage = gui_progress / 100.f;
            //y62
            if(gui_progress < 100){
                wxString msg = _L("Sending...");
                bool is_undisplay = false;
                m_status_bar->update_status(msg, is_undisplay, std::floor(10 + gui_progress * 0.9), true);
            }
            else{
                std::vector<std::string> dot = {"..", "....", "......"};
                for(int i = 0; i < 3; i++){
                    wxString msg = _L("Waiting for the printer's response") + dot[i];
                    bool is_undisplay = false;
                    m_status_bar->update_status(msg, is_undisplay, 100, true);
                    std::this_thread::sleep_for(std::chrono::milliseconds(500));
                }
            }
        },
        [this](wxString error) {
            show_status(PrintDialogStatus::PrintStatusPublicUploadFiled);
            update_print_status_msg(error, false, true);
        }
        );

    if (success)
    {
        bool is_switch_to_device = wxGetApp().app_config->get("switch to device tab after upload") == "true" ? true : false;
        if (is_switch_to_device) {
            for(int i = 3; i > 0; i--){
                if(m_is_canceled)
                    return;
                wxString msg = wxString::Format(_L("Successfully sent. Will automatically jump to the device page in %s s."), std::to_string(i));
                m_status_bar->update_status(msg, m_is_canceled, 100, true);
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
            wxString msg = _L("Switch to device tab...");
            m_status_bar->update_status(msg, m_is_canceled, 100, true);
            if (m_isNetMode) {
                wxGetApp().mainframe->m_printer_view->FormatNetUrl(machine_link_url, machine_ip, machine_is_special);
                wxGetApp().mainframe->m_printer_view->SetToggleBar(m_isNetMode);
                wxGetApp().app_config->set("machine_list_net", "1");
                wxGetApp().mainframe->m_printer_view->ShowNetPrinterButton();
            }
            else {
                wxGetApp().mainframe->m_printer_view->FormatUrl(machine_url);
                wxGetApp().mainframe->m_printer_view->SetToggleBar(m_isNetMode);
                wxGetApp().app_config->set("machine_list_net", "0");
                wxGetApp().mainframe->m_printer_view->ShowLocalPrinterButton();
            }
            wxGetApp().mainframe->select_tab(size_t(3));
        }
        else{
            for(int i = 3; i > 0; i--){
                if(m_is_canceled)
                    return;
                wxString msg = wxString::Format(_L("Successfully sent. Close current page in %s s."), std::to_string(i));
                m_status_bar->update_status(msg, m_is_canceled, 100, true);
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
        }
        EndDialog(wxID_CLOSE);
    }
}

void SendToPrinterDialog::clear_ip_address_config(wxCommandEvent& e)
{
    enable_prepare_mode = true;
    prepare_mode();
}

void SendToPrinterDialog::update_user_machine_list()
{
    NetworkAgent* m_agent = wxGetApp().getAgent();
    if (m_agent && m_agent->is_user_login()) {
        //B
        // boost::thread get_print_info_thread = Slic3r::create_thread([this, token = std::weak_ptr<int>(m_token)] {
        //     NetworkAgent* agent = wxGetApp().getAgent();
        //     unsigned int http_code;
        //     std::string body;
        //     int result = agent->get_user_print_info(&http_code, &body);
        //     CallAfter([token, this, result, body] {
        //         if (token.expired()) {return;}
        //         if (result == 0) {
        //             m_print_info = body;
        //         }
        //         else {
        //             m_print_info = "";
        //         }
        //         wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST);
        //         event.SetEventObject(this);
        //         wxPostEvent(this, event);
        //     });
        // });
    } else {
        wxCommandEvent event(EVT_UPDATE_USER_MACHINE_LIST);
        event.SetEventObject(this);
        wxPostEvent(this, event);
    }
}

void SendToPrinterDialog::on_refresh(wxCommandEvent &event)
{
    BOOST_LOG_TRIVIAL(info) << "m_printer_last_select: on_refresh";
     show_status(PrintDialogStatus::PrintStatusRefreshingMachineList);
     update_user_machine_list();
    /*todo refresh*/
    if (m_file_sys) {
        m_file_sys->Stop(true);
        m_file_sys.reset();
    }
}

void SendToPrinterDialog::on_print_job_cancel(wxCommandEvent &evt)
{
    BOOST_LOG_TRIVIAL(info) << "print_job: canceled";
    show_status(PrintDialogStatus::PrintStatusSendingCanceled);
    // enter prepare mode
    prepare_mode();
    m_is_canceled = true;
}

std::vector<std::string> SendToPrinterDialog::sort_string(std::vector<std::string> strArray)
{
    std::vector<std::string> outputArray;
    std::sort(strArray.begin(), strArray.end());
    std::vector<std::string>::iterator st;
    for (st = strArray.begin(); st != strArray.end(); st++) { outputArray.push_back(*st); }

    return outputArray;
}

bool  SendToPrinterDialog::is_timeout()
{
    if (timeout_count > 15 * 1000 / LIST_REFRESH_INTERVAL) {
        return true;
    }
    return false;
}

void  SendToPrinterDialog::reset_timeout()
{
    timeout_count = 0;
}

void SendToPrinterDialog::update_user_printer()
{
    // Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
    // if (!dev) return;

    // // update user print info
    // if (!m_print_info.empty()) {
    //     dev->parse_user_print_info(m_print_info);
    //     m_print_info = "";
    // }

    // // clear machine list
    // m_list.clear();
    // m_comboBox_printer->Clear();
    // std::vector<std::string>              machine_list;
    // wxArrayString                         machine_list_name;
    // std::map<std::string, MachineObject*> option_list;

    // option_list = dev->get_my_machine_list();

    // // same machine only appear once
    // for (auto it = option_list.begin(); it != option_list.end(); it++) {
    //     if (it->second && (it->second->is_online() || it->second->is_connected())) {
    //         machine_list.push_back(it->second->dev_name);
    //     }
    // }
    // machine_list = sort_string(machine_list);
    // for (auto tt = machine_list.begin(); tt != machine_list.end(); tt++) {
    //     for (auto it = option_list.begin(); it != option_list.end(); it++) {
    //         if (it->second->dev_name == *tt) {
    //             m_list.push_back(it->second);
    //             wxString dev_name_text = from_u8(it->second->dev_name);
    //             if (it->second->is_lan_mode_printer()) {
    //                 dev_name_text += "(LAN)";
    //             }
    //             machine_list_name.Add(dev_name_text);
    //             break;
    //         }
    //     }
    // }

    // m_comboBox_printer->Set(machine_list_name);

    // MachineObject* obj = dev->get_selected_machine();
    // if (obj) {
    //     m_printer_last_select = obj->dev_id;
    // } else {
    //     m_printer_last_select = "";
    // }

    // if (m_list.size() > 0) {
    //     // select a default machine
    //     if (m_printer_last_select.empty()) {
    //         m_printer_last_select = m_list[0]->dev_id;
    //         m_comboBox_printer->SetSelection(0);
    //         wxCommandEvent event(wxEVT_COMBOBOX);
    //         event.SetEventObject(m_comboBox_printer);
    //         wxPostEvent(m_comboBox_printer, event);
    //     }
    //     for (auto i = 0; i < m_list.size(); i++) {
    //         if (m_list[i]->dev_id == m_printer_last_select) {
    //             m_comboBox_printer->SetSelection(i);
    //             wxCommandEvent event(wxEVT_COMBOBOX);
    //             event.SetEventObject(m_comboBox_printer);
    //             wxPostEvent(m_comboBox_printer, event);
    //         }
    //     }
    // }
    // else {
    //     m_printer_last_select = "";
    //     m_comboBox_printer->SetTextLabel("");
    // }

    // BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "for send task, current printer id =  " << m_printer_last_select << std::endl;

    // y16
    m_comboBox_printer->Clear();
    machine_list_local.clear();
    machine_list_link.clear();

    PresetBundle& preset_bundle = *wxGetApp().preset_bundle;
    const std::deque<PhysicalPrinter>& ph_printers = preset_bundle.physical_printers();
    for (size_t i = 0; i < ph_printers.size(); i++)
    {
        //y24
        Machine_info machine;
        const PhysicalPrinter& py_printer = ph_printers[i];
        machine.name = py_printer.name;
        machine.url = py_printer.config.opt_string("print_host");
        machine.ip = py_printer.config.opt_string("print_host");
        machine.type = py_printer.config.opt_string("preset_name");
        machine.display_name = machine.name + " (" + machine.ip + ")";
        machine.apikey = py_printer.config.opt_string("printhost_apikey");
        machine_list_local.push_back(machine);
    }

#if QDT_RELEASE_TO_PUBLIC
    if (wxGetApp().app_config->get("user_token") != "")
    {
        auto m_devices = wxGetApp().get_devices();
        for (const auto& device : m_devices) {
            //y24
            Machine_info machine;
            machine.name = device.device_name;
            machine.url = device.url;
            machine.ip = device.local_ip;
            machine.type = device.machine_type;
            if (machine.type.empty())
            {
                std::size_t found = device.device_name.find('@');
                if (found != std::string::npos)
                {
                    machine.type = device.device_name.substr(found + 1);
                }
            }
            machine.display_name = machine.name + " (" + machine.ip + ")";
            machine.link_url = device.link_url;
            machine.is_special = device.isSpecialMachine;
            machine_list_link.push_back(machine);
        }
    }
#endif

    //y58
    show_status(PrintDialogStatus::PrintStatusInit);

    m_switch_button->SetValue(m_isNetMode);
    wxCommandEvent event(wxEVT_TOGGLEBUTTON, m_switch_button->GetId());
    event.SetEventObject(m_switch_button);
    event.SetInt(m_switch_button->GetValue());
    m_switch_button->GetEventHandler()->ProcessEvent(event);
}

void SendToPrinterDialog::update_printer_combobox(wxCommandEvent &event)
{
    show_status(PrintDialogStatus::PrintStatusInit);
    update_user_printer();
}

void SendToPrinterDialog::on_timer(wxTimerEvent &event)
{
    update_show_status();
}

void SendToPrinterDialog::on_selection_changed(wxCommandEvent &event)
{
//     /* reset timeout and reading printer info */
//     //m_status_bar->reset();
//     timeout_count      = 0;

//     auto selection = m_comboBox_printer->GetSelection();
//     DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
//     if (!dev) return;
    // m_tcp_try_connect  = true;
    // m_tutk_try_connect = false;
    // m_ftp_try_connect  = false;

    // m_connect_try_times = 0;
//     MachineObject* obj = nullptr;
//     for (int i = 0; i < m_list.size(); i++) {
//         if (i == selection) {
//             m_printer_last_select = m_list[i]->dev_id;
//             obj = m_list[i];
//             BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "for send task, current printer id =  " << QDTCrossTalk::Crosstalk_DevId(m_printer_last_select) << std::endl;
//             break;
//         }
//     }

//     if (obj && !obj->get_lan_mode_connection_state()) {
//         obj->command_get_version();
//         obj->command_request_push_all();
//         if (!dev->get_selected_machine()) {
//             dev->set_selected_machine(m_printer_last_select, true);
//             if (m_file_sys) m_file_sys.reset();
//         }else if (dev->get_selected_machine()->dev_id != m_printer_last_select) {
//             m_ability_list.clear();
//             //update_storage_list(std::vector<std::string>());
//             dev->set_selected_machine(m_printer_last_select, true);
//             if (m_file_sys) m_file_sys.reset();
//         }
//     }
//     else {
//         BOOST_LOG_TRIVIAL(error) << "on_selection_changed dev_id not found";
//         return;
//     }

//     update_show_status();

    //y24
    std::string selection_name = into_u8(m_comboBox_printer->GetValue());
    if (!selection_name.empty())
    {
        if (!m_isNetMode)
        {
            for (auto machine : machine_list_local)
            {
                if (machine.display_name != selection_name)
                    continue;
                else if (preset_typename_normalized.find(NormalizeVendor(machine.type)) != std::string::npos)
                {
                    Enable_Send_Button(true);
                    update_print_status_msg(wxEmptyString, false, false);
                    break;
                }
                else
                {
                    Enable_Send_Button(false);
                    wxString msg_text = wxString::Format(_L("The selected printer (%s) is incompatible with the chosen printer profile in the slicer (%s)."), machine.type, preset_typename);
                    update_print_status_msg(msg_text, true, true);
                    break;
                }
            }
        }
        else
        {
            for (auto machine : machine_list_link)
            {
                if (machine.display_name != selection_name)
                    continue;
                else if (preset_typename_normalized.find(NormalizeVendor(machine.type)) != std::string::npos)
                {
                    Enable_Send_Button(true);
                    update_print_status_msg(wxEmptyString, false, false);
                    break;
                }
                else
                {
                    Enable_Send_Button(false);
                    wxString msg_text = wxString::Format(_L("The selected printer (%s) is incompatible with the chosen printer profile in the slicer (%s)."), machine.type, preset_typename);
                    update_print_status_msg(msg_text, true, true);
                    break;
                }
            }
        }
    }
    else
        Enable_Send_Button(false);
}

void SendToPrinterDialog::update_show_status()
{
    NetworkAgent* agent = Slic3r::GUI::wxGetApp().getAgent();
    DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
    if (!agent) return;
    if (!dev) return;
    MachineObject* obj_ = dev->get_my_machine(m_printer_last_select);
    if (!obj_) {
        if (agent) {
            if (agent->is_user_login()) {
                show_status(PrintDialogStatus::PrintStatusInvalidPrinter);
            }
        }
        return;
    }

    /* check cloud machine connections */
    if (!obj_->is_lan_mode_printer()) {
        if (!agent->is_server_connected()) {
            show_status(PrintDialogStatus::PrintStatusConnectingServer);
            reset_timeout();
            return;
        }
    }

    if (!obj_->is_info_ready()) {
        if (is_timeout()) {
            show_status(PrintDialogStatus::PrintStatusReadingTimeout);
            return;
        }
        else {
            timeout_count++;
            show_status(PrintDialogStatus::PrintStatusReading);
            return;
        }
        return;
    }

    reset_timeout();

    // reading done
    if (is_blocking_printing(obj_)) {
        show_status(PrintDialogStatus::PrintStatusUnsupportedPrinter);
        return;
    }
    else if (obj_->is_in_upgrading()) {
        show_status(PrintDialogStatus::PrintStatusInUpgrading);
        return;
    }
    else if (obj_->is_system_printing()) {
        show_status(PrintDialogStatus::PrintStatusInSystemPrinting);
        return;
    }

    // check sdcard when if lan mode printer
   /* if (obj_->is_lan_mode_printer()) {
    }*/
	if (obj_->get_sdcard_state() == MachineObject::SdcardState::NO_SDCARD) {
		show_status(PrintDialogStatus::PrintStatusNoSdcard);
		return;
	}


    if (!obj_->is_support_send_to_sdcard) {
        show_status(PrintDialogStatus::PrintStatusNotSupportedSendToSDCard);
        return;
    }

    if (!m_is_in_sending_mode) {
        if (!obj_->is_support_brtc || m_ftp_try_connect) {
            if (m_file_sys) {
                m_device_select.clear();
                m_file_sys->Stop(true);
                m_file_sys.reset();
            }
            BOOST_LOG_TRIVIAL(info) << "m_ftp_try_connect is ok" << m_ftp_try_connect;

            // add log
            show_status(PrintDialogStatus::PrintStatusReadingFinished);
            return;
        } else/* if (obj_->connection_type() == "cloud")*/ {
            std::string dev_id = obj_->dev_ip;
            if (m_file_sys) {
                if (dev_id == m_device_select) {
                    if ((m_waiting_enable && IsEnabled()) || (m_waiting_support && obj_->get_file_remote()))
                    {
                        m_file_sys->Retry();
                        BOOST_LOG_TRIVIAL(info) << "m_file_sys  Retry success!" ;
                    }
                    return;
                } else {
                    m_file_sys->Stop(true);
                }
            }

            m_device_select.swap(dev_id);
            m_file_sys = boost::make_shared<PrinterFileSystem>();
            m_file_sys->Attached();

            m_file_sys->Bind(EVT_STATUS_CHANGED, [this, wfs = boost::weak_ptr(m_file_sys),obj_](auto e) {
                e.Skip();
                boost::shared_ptr fs(wfs.lock());
                if (!fs) return;

                wxString msg;
                int      status = e.GetInt();
                int      extra  = e.GetExtraLong();
                switch (status) {
                case PrinterFileSystem::Initializing:
                case PrinterFileSystem::Connecting: show_status(PrintDialogStatus::PrintStatusConnecting); break;

                case PrinterFileSystem::ListSyncing: {
                    show_status(PrintDialogStatus::PrintStatusReading);
                    boost::uint32_t seq = fs->RequestMediaAbility(3);

                    if (m_task_timer && m_task_timer->IsRunning())
                        m_task_timer->Stop();

                    m_task_timer.reset(new wxTimer());
                    m_task_timer->SetOwner(this);

                    this->Bind(wxEVT_TIMER, [this, wfs_1 = boost::weak_ptr(fs), seq](auto e) {
                            show_status(PrintDialogStatus::PrintStatusPublicInitFailed);
                            update_print_status_msg(_L("Media capability acquisition timeout, please check if the firmware version supports it."), true, true);
                        }, m_task_timer->GetId());
                    m_task_timer->StartOnce(timeout_period);

                    break;
                }
                case PrinterFileSystem::Failed: {
                    if (m_connect_try_times < 2) {
                        bool is_lan = (obj_->connection_type() == "lan");

                         m_tcp_try_connect = false;

                         if (is_lan) {
                             m_ftp_try_connect = true;
                             m_tutk_try_connect = false;
                         } else {
                             if (m_connect_try_times == 0) {
                                 m_ftp_try_connect  = false;
                                 m_tutk_try_connect = true;
                             } else {
                                 m_ftp_try_connect  = true;
                                 m_tutk_try_connect = false;
                             }
                         }
                        BOOST_LOG_TRIVIAL(info) << "connect  failed"  ;
                        BOOST_LOG_TRIVIAL(info) << "m_ftp_try_connect1 is  " << m_ftp_try_connect;
                        BOOST_LOG_TRIVIAL(info) << "m_tutk_try_connect1 is  " << m_tutk_try_connect ;
                        BOOST_LOG_TRIVIAL(info) << "m_tcp_try_connect1 is  " << m_tcp_try_connect;
                    }
                    else
                        msg = _L("Please check the network and try again, You can restart or update the printer if the issue persists.");

                    fs->Stop();
                    m_connect_try_times++;
                    BOOST_LOG_TRIVIAL(info) << "m_connect_try_times is  " << m_connect_try_times;

                    break;
                }

                case PrinterFileSystem::Reconnecting: show_status(PrintDialogStatus::PrintStatusReconnecting);

                }

                if (!msg.empty()) {
                    show_status(PrintDialogStatus::PrintStatusPublicInitFailed);
                    update_print_status_msg(msg, false, true);
                }

                if (e.GetInt() == PrinterFileSystem::Initializing) {
                    CallAfter([=] {
                        boost::shared_ptr fs(wfs.lock());
                        if (!fs) return;
                        fetchUrl(boost::weak_ptr(fs));
                    });
                }
            });

        m_file_sys->Bind(EVT_MEDIA_ABILITY_CHANGED, [this, wfs = boost::weak_ptr(m_file_sys)](auto e) {
            boost::shared_ptr fs(wfs.lock());
            if (!fs) return;

            if (m_task_timer && m_task_timer->IsRunning()) {
                m_task_timer->Stop();
                m_task_timer.reset();
            }

            m_ability_list = fs->GetMediaAbilityList();

            if (e.GetInt() == PrinterFileSystem::RequestMediaAbilityStatus::S_SUCCESS) {
                //update_storage_list(m_ability_list);
                show_status(PrintDialogStatus::PrintStatusReadingFinished);
            } else {
                show_status(PrintDialogStatus::PrintStatusPublicInitFailed);
                update_print_status_msg(e.GetString(), false, true);
            }
        });

        m_file_sys->Bind(EVT_UPLOADING, [this, wfs = boost::weak_ptr(m_file_sys)](auto e) {
            boost::shared_ptr fs(wfs.lock());
            if (!fs) return;
            int progress = e.GetInt();
            bool cancelled = false;
            wxString msg       = _L("Sending...");
            m_status_bar->update_status(msg, cancelled, 10 + std::floor(progress * 0.9), true);

           if (m_task_timer && m_task_timer->IsRunning()) m_task_timer->Stop();

           if (progress == 99) {
               m_task_timer.reset(new wxTimer());
               m_task_timer->SetOwner(this);

               this->Bind(
                   wxEVT_TIMER,
                   [this, wfs = boost::weak_ptr(m_file_sys)](auto e) {
                       show_status(PrintDialogStatus::PrintStatusPublicUploadFiled);
                       boost::shared_ptr fs(wfs.lock());
                       if (!fs) return;
                       fs->CancelUploadTask(false);
                       update_print_status_msg(_L("File upload timed out. Please check if the firmware version supports this operation or verify if the printer is functioning properly."), false, true);
                   },
                   m_task_timer->GetId());
               m_task_timer->StartOnce(timeout_period);
           }
        });
        m_file_sys->Bind(EVT_UPLOAD_CHANGED, [this, wfs = boost::weak_ptr(m_file_sys)](auto e) {
            boost::shared_ptr fs(wfs.lock());
            if (!fs) return;

            if (m_task_timer && m_task_timer->IsRunning()) m_task_timer->Stop();

            if (e.GetInt() == PrinterFileSystem::FF_UPLOADDONE) {
                show_status(PrintDialogStatus::PrintStatusReadingFinished);
                wxCommandEvent *evt = new wxCommandEvent(m_plater->get_send_finished_event());
                evt->SetString(from_u8(m_current_project_name.utf8_string()));
                wxQueueEvent(m_plater, evt);
            } else if (e.GetInt() == PrinterFileSystem::FF_UPLOADCANCEL) {
                show_status(PrintDialogStatus::PrintStatusPublicUploadFiled);
                wxString err_msg = e.GetString();
                if (err_msg.IsEmpty())
                    err_msg = _L("Sending failed, please try again!");
                update_print_status_msg(err_msg, false, true);
            }
        });
        m_file_sys->Start();
        }
    }
}

bool SendToPrinterDialog::is_blocking_printing(MachineObject* obj_)
{
    DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
    if (!dev) return true;

    PresetBundle* preset_bundle = wxGetApp().preset_bundle;
    auto source_model = preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle);
    auto target_model = obj_->printer_type;

    if (source_model != target_model) {
        std::vector<std::string> compatible_machine = dev->get_compatible_machine(target_model);
        vector<std::string>::iterator it = find(compatible_machine.begin(), compatible_machine.end(), source_model);
        if (it == compatible_machine.end()) {
            return true;
        }
    }

    return false;
}

void SendToPrinterDialog::Enable_Refresh_Button(bool en)
{
    if (!en) {
        if (m_button_refresh->IsEnabled()) {
            m_button_refresh->Disable();
            m_button_refresh->SetBackgroundColor(wxColour(0x90, 0x90, 0x90));
            m_button_refresh->SetBorderColor(wxColour(0x90, 0x90, 0x90));
        }
    } else {
        if (!m_button_refresh->IsEnabled()) {
            m_button_refresh->Enable();
            m_button_refresh->SetBackgroundColor(btn_bg_enable);
            m_button_refresh->SetBorderColor(btn_bg_enable);
        }
    }
}

void SendToPrinterDialog::show_status(PrintDialogStatus status, std::vector<wxString> params)
{
	if (m_print_status != status)
		BOOST_LOG_TRIVIAL(info) << "select_machine_dialog: show_status = " << status;
	m_print_status = status;

	// m_comboBox_printer
	if (status == PrintDialogStatus::PrintStatusRefreshingMachineList)
		m_comboBox_printer->Disable();
	else
		m_comboBox_printer->Enable();


    //connecting
    if(status == PrintDialogStatus::PrintStatusConnecting)
    {
        m_connecting_printer_msg->SetLabel(_L("Try to connect"));
        update_print_status_msg(wxEmptyString, true, true);
        m_connecting_panel->Show();
        m_animaicon->Play();

        Layout();
        Enable_Send_Button(false);
        Enable_Refresh_Button(true);
        return;

    } else if (status == PrintDialogStatus::PrintStatusReconnecting) {
        m_connecting_printer_msg->SetLabel(_L("Connection failed. Click the icon to retry"));
            update_print_status_msg(wxEmptyString, true, true);
            m_connecting_panel->Show();
            m_animaicon->Stop();
            m_animaicon->Enable();

            Layout();
            Enable_Send_Button(false);
            Enable_Refresh_Button(true);
            return;
    }
    else {
        m_connecting_panel->Hide();
    }


	// m_panel_warn m_simplebook
	if (status == PrintDialogStatus::PrintStatusSending) {
		sending_mode();
	}

	// other
	if (status == PrintDialogStatus::PrintStatusInit) {
		update_print_status_msg(wxEmptyString, false, false);
		Enable_Send_Button(false);
		Enable_Refresh_Button(true);
	}
	else if (status == PrintDialogStatus::PrintStatusInvalidPrinter) {
		update_print_status_msg(wxEmptyString, true, true);
		Enable_Send_Button(false);
		Enable_Refresh_Button(true);
	}
	else if (status == PrintDialogStatus::PrintStatusConnectingServer) {
		wxString msg_text = _L("Connecting to server");
		update_print_status_msg(msg_text, true, true);
		Enable_Send_Button(true);
		Enable_Refresh_Button(true);
    }
    else if (status == PrintDialogStatus::PrintStatusReading) {
        wxString msg_text = _L("Synchronizing device information");
        update_print_status_msg(msg_text, false, true);
        Enable_Send_Button(false);
        Enable_Refresh_Button(true);
    }

	else if (status == PrintDialogStatus::PrintStatusReadingFinished) {
		update_print_status_msg(wxEmptyString, false, true);
		Enable_Send_Button(true);
		Enable_Refresh_Button(true);
	}
	else if (status == PrintDialogStatus::PrintStatusReadingTimeout) {
		wxString msg_text = _L("Synchronizing device information time out");
		update_print_status_msg(msg_text, true, true);
		Enable_Send_Button(true);
		Enable_Refresh_Button(true);
	}
	else if (status == PrintDialogStatus::PrintStatusInUpgrading) {
		wxString msg_text = _L("Cannot send the print task when the upgrade is in progress");
		update_print_status_msg(msg_text, true, true);
		Enable_Send_Button(false);
		Enable_Refresh_Button(true);
	}
    else if (status == PrintDialogStatus::PrintStatusUnsupportedPrinter) {
        wxString msg_text = _L("The selected printer is incompatible with the chosen printer presets.");
        update_print_status_msg(msg_text, true, true);
        Enable_Send_Button(false);
        Enable_Refresh_Button(true);
    }
	else if (status == PrintDialogStatus::PrintStatusRefreshingMachineList) {
		update_print_status_msg(wxEmptyString, false, true);
		Enable_Send_Button(false);
		Enable_Refresh_Button(false);
	}
	else if (status == PrintDialogStatus::PrintStatusSending) {
		Enable_Send_Button(false);
		Enable_Refresh_Button(false);
	}
	else if (status == PrintDialogStatus::PrintStatusSendingCanceled) {
		Enable_Send_Button(true);
		Enable_Refresh_Button(true);
	}
	else if (status == PrintDialogStatus::PrintStatusNoSdcard) {
		wxString msg_text = _L("Storage needs to be inserted before send to printer.");
		update_print_status_msg(msg_text, true, true);
		Enable_Send_Button(false);
		Enable_Refresh_Button(true);
    }
    else if (status == PrintDialogStatus::PrintStatusNotOnTheSameLAN) {
        wxString msg_text = _L("The printer is required to be in the same LAN as QIDI Studio.");
        update_print_status_msg(msg_text, true, true);
        Enable_Send_Button(false);
        Enable_Refresh_Button(true);
    }
    else if (status == PrintDialogStatus::PrintStatusNotSupportedSendToSDCard) {
        wxString msg_text = _L("The printer does not support sending to printer storage.");
        update_print_status_msg(msg_text, true, true);
        Enable_Send_Button(false);
        Enable_Refresh_Button(true);
    } else if (status == PrintDialogStatus::PrintStatusPublicInitFailed) {
        Enable_Send_Button(false);
        Enable_Refresh_Button(true);
    } else if (status == PrintDialogStatus::PrintStatusPublicUploadFiled) {
        prepare_mode();
        Enable_Send_Button(true);
        Enable_Refresh_Button(true);
    }
    else {
		Enable_Send_Button(true);
		Enable_Refresh_Button(true);
    }
}


void SendToPrinterDialog::Enable_Send_Button(bool en)
{
    if (!en) {
        if (m_button_ensure->IsEnabled()) {
            m_button_ensure->Disable();
            m_button_ensure->SetBackgroundColor(wxColour(0x90, 0x90, 0x90));
            m_button_ensure->SetBorderColor(wxColour(0x90, 0x90, 0x90));
            m_storage_panel->Hide();
        }
    } else {
        if (!m_button_ensure->IsEnabled()) {
            m_button_ensure->Enable();
            m_button_ensure->SetBackgroundColor(btn_bg_enable);
            m_button_ensure->SetBorderColor(btn_bg_enable);
            m_storage_panel->Show();
        }
    }
}

void SendToPrinterDialog::on_dpi_changed(const wxRect &suggested_rect)
{
    m_button_refresh->SetMinSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE);
    m_button_refresh->SetCornerRadius(FromDIP(12));
    m_button_ensure->SetMinSize(SELECT_MACHINE_DIALOG_BUTTON_SIZE);
    m_button_ensure->SetCornerRadius(FromDIP(12));
    m_status_bar->msw_rescale();
    Fit();
    Refresh();
}

void SendToPrinterDialog::set_default()
{
    //project name
    m_rename_switch_panel->SetSelection(0);

    //y61
    wxString filename = "";
    if (wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_string("filename_format") == "{input_filename_base}.gcode"){
        try{
            filename = m_plater->get_export_gcode_filename("", true, m_print_plate_idx == PLATE_ALL_IDX ? true : false);
        }
        catch (const Slic3r::PlaceholderParserError& ex) {
            // Show the error with monospaced font.
            show_error(this, ex.what(), true);
        }
        catch (const std::exception& ex) {
            show_error(this, ex.what(), false);
        }
    }
    else{
        try{
            filename = m_plater->get_output_filename();
        }
        catch (const Slic3r::PlaceholderParserError& ex) {
            // Show the error with monospaced font.
            show_error(this, ex.what(), true);
        }
        catch (const std::exception &ex) {
            show_error(this, ex.what(), false);
        }
    }

    if (m_print_plate_idx == PLATE_ALL_IDX && filename.empty()) {
        filename = _L("Untitled");
    }

    if (filename.empty()) {
        filename = m_plater->get_export_gcode_filename("", true);
        if (filename.empty()) filename = _L("Untitled");
    }

    fs::path filename_path(filename.c_str());
    //y52
    wxString file_name = from_u8(filename_path.filename().string());
    if (file_name.find(_L("Untitled")) != wxString::npos) {
        PartPlate* part_plate = m_plater->get_partplate_list().get_plate(m_print_plate_idx);
        if (part_plate) {
            if (std::vector<ModelObject*> objects = part_plate->get_objects_on_this_plate(); objects.size() > 0) {
                file_name = from_u8(objects[0]->name);
                for (int i = 1; i < objects.size(); i++) {
                    file_name += " + " + from_u8(objects[i]->name);
                }
            }
        }
    }
    if (file_name.size() > 80) {
        file_name = file_name.substr(0, 80) + "...";
    }

    m_current_project_name = file_name;
    if(m_current_project_name.find(".gcode") != wxString::npos)
        m_current_project_name = m_current_project_name.substr(0, m_current_project_name.size() - 6);

    //unsupported character filter
    //y51
    m_current_project_name = from_u8(filter_characters(m_current_project_name.ToUTF8().data(), "<>[]:\\|?*\""));

    m_rename_text->SetLabelText(m_current_project_name);
    m_rename_normal_panel->Layout();

    enable_prepare_mode = true;
    prepare_mode();

    //clear combobox
    m_list.clear();
    m_comboBox_printer->Clear();
    m_printer_last_select = "";
    m_print_info = "";
    m_comboBox_printer->SetValue(wxEmptyString);
    m_comboBox_printer->Enable();
    // rset status bar
    m_status_bar->reset();

    NetworkAgent* agent = wxGetApp().getAgent();
    if (agent) {
        if (agent->is_user_login()) {
            show_status(PrintDialogStatus::PrintStatusInit);
        }
    }

    // thumbmail
    //wxBitmap bitmap;
    ThumbnailData &data   = m_plater->get_partplate_list().get_curr_plate()->thumbnail_data;
    if (data.is_valid()) {
        wxImage image(data.width, data.height);
        image.InitAlpha();
        for (unsigned int r = 0; r < data.height; ++r) {
            unsigned int rr = (data.height - 1 - r) * data.width;
            for (unsigned int c = 0; c < data.width; ++c) {
                unsigned char *px = (unsigned char *) data.pixels.data() + 4 * (rr + c);
                image.SetRGB((int) c, (int) r, px[0], px[1], px[2]);
                image.SetAlpha((int) c, (int) r, px[3]);
            }
        }
        image  = image.Rescale(FromDIP(256), FromDIP(256));
        m_thumbnailPanel->set_thumbnail(image);
    }

    std::vector<std::string> materials;
    std::vector<std::string> display_materials;
    {
        auto preset_bundle = wxGetApp().preset_bundle;
        for (auto filament_name : preset_bundle->filament_presets) {
            for (auto iter = preset_bundle->filaments.lbegin(); iter != preset_bundle->filaments.end(); iter++) {
                if (filament_name.compare(iter->name) == 0) {
                    std::string display_filament_type;
                    std::string filament_type = iter->config.get_filament_type(display_filament_type);
                    display_materials.push_back(display_filament_type);
                    materials.push_back(filament_type);
                }
            }
        }
    }

    m_scrollable_region->Layout();
    m_scrollable_region->Fit();
    Layout();
    Fit();


    wxSize screenSize = wxGetDisplaySize();
    auto dialogSize = this->GetSize();


    // basic info
    auto       aprint_stats = m_plater->get_partplate_list().get_current_fff_print().print_statistics();
    wxString   time;
    PartPlate *plate = m_plater->get_partplate_list().get_curr_plate();
    if (plate) {
        if (plate->get_slice_result()) { time = wxString::Format("%s", short_time(get_time_dhms(plate->get_slice_result()->print_statistics.modes[0].time))); }
    }

    char weight[64];
    if (wxGetApp().app_config->get("use_inches") == "1") {
        ::sprintf(weight, "  %.2f oz", aprint_stats.total_weight*0.035274);
    }else{
        ::sprintf(weight, "  %.2f g", aprint_stats.total_weight);
    }

    m_stext_time->SetLabel(time);
    m_stext_weight->SetLabel(weight);
}

bool SendToPrinterDialog::Show(bool show)
{
    show_status(PrintDialogStatus::PrintStatusInit);

    // set default value when show this dialog
    if (show) {
        m_ability_list.clear();
        //update_storage_list(std::vector<std::string>());
        set_default();
        update_user_machine_list();
    }



    if (show) {
        m_refresh_timer->Start(LIST_REFRESH_INTERVAL);
        m_tcp_try_connect   = true;
        m_ftp_try_connect   = false;
        m_tutk_try_connect  = false;
     //BOOST_LOG_TRIVIAL(info) << "m_ftp_try_connect is  " << m_ftp_try_connect << boost::stacktrace::stacktrace();
        m_connect_try_times = 0;
    } else {
        m_refresh_timer->Stop();
    }

    Layout();
    Fit();
    if (show) { CenterOnParent(); }

    if (m_file_sys) {
        m_waiting_enable = false;
        m_waiting_support = false;
        show ? m_file_sys->Start() : m_file_sys->Stop();
    }
    return DPIDialog::Show(show);
}

extern wxString hide_passwd(wxString url, std::vector<wxString> const &passwords);
extern void     refresh_agora_url(char const *device, char const *dev_ver, char const *channel, void *context, void (*callback)(void *context, char const *url));

void SendToPrinterDialog::fetchUrl(boost::weak_ptr<PrinterFileSystem> wfs)
{
    boost::shared_ptr fs(wfs.lock());
    if (!fs) return;

    if (!IsEnabled()) {
        m_waiting_enable = true;
        fs->SetUrl("0");
        return;
    }

    m_waiting_enable = false;
    DeviceManager *dm = GUI::wxGetApp().getDeviceManager();
    MachineObject *obj = dm->get_selected_machine();

    if (obj == nullptr) {
        fs->SetUrl("0");
        return;
    }

    std::string dev_ver = obj->get_ota_version();
    std::string dev_id = obj->dev_id;
    int remote_proto = obj->get_file_remote();
    if (!remote_proto) {
        m_waiting_support = true;
        fs->SetUrl("0");
        return;
    }

    if (obj->is_camera_busy_off()) {
        fs->SetUrl("0");
        return;
    }

    m_waiting_support           = false;
    NetworkAgent *agent         = wxGetApp().getAgent();
    std::string   agent_version = agent ? agent->get_version() : "";



       if (agent) {
            if (m_tcp_try_connect) {
                std::string devIP      = obj->dev_ip;
                std::string accessCode = obj->get_access_code();
                std::string tcp_url    = "qidi:///local/" + devIP + "?port=6000&user=" + "qdtp" + "&passwd=" + accessCode;
                CallAfter([=] {
                    boost::shared_ptr fs(wfs.lock());
                    if (!fs) return;
                    if (boost::algorithm::starts_with(tcp_url, "qidi:///")) {
                        fs->SetUrl(tcp_url);
                    } else {
                        fs->SetUrl("3");
                    }
                });
            }
            else if (m_tutk_try_connect){
                std::string protocols[] = {"", "\"tutk\"", "\"agora\"", "\"tutk\",\"agora\""};
                agent->get_camera_url(obj->dev_id + "|" + dev_ver + "|" + protocols[1], [this, wfs, m = dev_id, v = agent->get_version(), dv = dev_ver](std::string url) {
                    if (boost::algorithm::starts_with(url, "qidi:///")) {
                        url += "&device=" + m;
                        url += "&net_ver=" + v;
                        url += "&dev_ver=" + dv;
                        url += "&refresh_url=" + boost::lexical_cast<std::string>(&refresh_agora_url);
                        url += "&cli_id=" + wxGetApp().app_config->get("slicer_uuid");
                        url += "&cli_ver=" + std::string(SLIC3R_VERSION);
                    }
#if !QDT_RELEASE_TO_PUBLIC
                    BOOST_LOG_TRIVIAL(info) << "SendToPrinter::fetchUrl: camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="});
                    std::cout << "SendToPrinter::fetchUrl: camera_url: " << hide_passwd(url, {"?uid=", "authkey=", "passwd="});
#endif
                    CallAfter([=] {
                        boost::shared_ptr fs(wfs.lock());
                        if (!fs) return;
                        if (boost::algorithm::starts_with(url, "qidi:///")) {
                            fs->SetUrl(url);
                        } else {
                            fs->SetUrl("3");
                        }
                    });
                });
                }
            }

    return;
}

SendToPrinterDialog::~SendToPrinterDialog()
{
    delete m_refresh_timer;
    if (m_task_timer && m_task_timer->IsRunning())
        m_task_timer->Stop();
}

//y24
std::string SendToPrinterDialog::NormalizeVendor(const std::string& str)
{
    std::string normalized;
    for (char c : str) {
        if (std::isalnum(c)) {
            normalized += std::tolower(c);
        }
    }
    return normalized;
}

}
}