#include <string>
#include <gtk/gtk.h>
#include <pulse/pulseaudio.h>


////////////////////////////build window////////////////////////////

GtkWidget *window;

GtkWidget *fixed;
GtkWidget *loopbtn;
GtkWidget *unloopbtn;

int mic_image_size= 128;
std::string loop_image_dir = "/etc/micassistant/loop.png";
std::string unloop_image_dir = "/etc/micassistant/unloop.png";    


bool is_looping = false;
void load_pa_loopback_cb(pa_context *ctx, uint idx, void *userdata) {
    is_looping = true;
    
    pa_mainloop_api *pa_mlapi = (pa_mainloop_api *)userdata;
    pa_mlapi->quit(pa_mlapi, 0);
}
bool load_pa_loopback(){
    if(is_looping) return false;
    
    pa_mainloop *paml = pa_mainloop_new();
    if(paml==NULL) return false;
    pa_mainloop_api *pamlapi = pa_mainloop_get_api(paml);
    if(pamlapi==NULL) return false;
    pa_context *pactx = pa_context_new(pamlapi, "set_active_ai_vol");
    if(pactx==NULL) return false;
    if(pa_context_connect(pactx, NULL, PA_CONTEXT_NOFLAGS, NULL)<0) return false;
    while(pa_context_get_state(pactx)!=PA_CONTEXT_READY) pa_mainloop_iterate(paml, 1, NULL);
    
    pa_operation *opt = pa_context_load_module(pactx, "module-loopback", "latency_msec=1", load_pa_loopback_cb, pamlapi);
    pa_operation_unref(opt);
    pa_mainloop_run(paml, NULL);
    
    pa_context_disconnect(pactx);
    pa_context_unref(pactx);
    pa_mainloop_free(paml);
    
    return is_looping;
}

bool find_loopback = false;
void issuccess_cb(pa_context *ctx, int issuccess, void *userdata){
    if(issuccess){
        is_looping = false;
    }
  
    pa_mainloop_api *pa_mlapi = (pa_mainloop_api *)userdata;
    pa_mlapi->quit(pa_mlapi, 0);
}
void unload_pa_loopback_cb(pa_context* ctx, const pa_module_info* i, int eol, void* userdata){
    if(i){
        if(strcmp(i->name, "module-loopback")==0){
            find_loopback = true;
            pa_context_unload_module(ctx, i->index, issuccess_cb, userdata);
        }
    }
    if(eol){
        if(!find_loopback){
            pa_mainloop_api *pa_mlapi = (pa_mainloop_api *)userdata;
            pa_mlapi->quit(pa_mlapi, 0);
        }
    }
}
bool unload_pa_loopback(){
    if(!is_looping) return false;
    
    pa_mainloop *paml = pa_mainloop_new();
    if(paml==NULL) return false;
    pa_mainloop_api *pamlapi = pa_mainloop_get_api(paml);
    if(pamlapi==NULL) return false;
    pa_context *pactx = pa_context_new(pamlapi, "set_active_ai_vol");
    if(pactx==NULL) return false;
    if(pa_context_connect(pactx, NULL, PA_CONTEXT_NOFLAGS, NULL)<0) return false;
    while(pa_context_get_state(pactx)!=PA_CONTEXT_READY) pa_mainloop_iterate(paml, 1, NULL);
    
    find_loopback = false;
    pa_operation *opt = pa_context_get_module_info_list(pactx, unload_pa_loopback_cb, pamlapi);
    pa_operation_unref(opt);
    pa_mainloop_run(paml, NULL);
    
    pa_context_disconnect(pactx);
    pa_context_unref(pactx);
    pa_mainloop_free(paml);
    
    return !is_looping;
}

void search_pa_loopback_cb(pa_context* ctx, const pa_module_info* i, int eol, void* userdata){
    if(i){
        if(strcmp(i->name, "module-loopback")==0)
            find_loopback = true;
    }
    if(eol){
        pa_mainloop_api *pa_mlapi = (pa_mainloop_api *)userdata;
        pa_mlapi->quit(pa_mlapi, 0);
    }
}
bool search_pa_loopback(){    
    pa_mainloop *paml = pa_mainloop_new();
    if(paml==NULL) return false;
    pa_mainloop_api *pamlapi = pa_mainloop_get_api(paml);
    if(pamlapi==NULL) return false;
    pa_context *pactx = pa_context_new(pamlapi, "set_active_ai_vol");
    if(pactx==NULL) return false;
    if(pa_context_connect(pactx, NULL, PA_CONTEXT_NOFLAGS, NULL)<0) return false;
    while(pa_context_get_state(pactx)!=PA_CONTEXT_READY) pa_mainloop_iterate(paml, 1, NULL);
    
    find_loopback = false;
    pa_operation *opt = pa_context_get_module_info_list(pactx, search_pa_loopback_cb, pamlapi);
    pa_operation_unref(opt);
    pa_mainloop_run(paml, NULL);
    
    pa_context_disconnect(pactx);
    pa_context_unref(pactx);
    pa_mainloop_free(paml);
    
    return find_loopback;
}

void loopbtn_Click(GtkWidget *button, gpointer data){
    if(unload_pa_loopback()){
        gtk_widget_show(unloopbtn);
        gtk_widget_hide(loopbtn);
    }
}

void unloopbtn_Click(GtkWidget *button, gpointer data){
    if(load_pa_loopback()){
        gtk_widget_show(loopbtn);
        gtk_widget_hide(unloopbtn);
    }
}

void buildWindow(){
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "K歌助手");
    gtk_window_set_default_size(GTK_WINDOW(window), 138, 138);
    gtk_container_set_border_width(GTK_CONTAINER(window), 5);
    gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    
    // build fixed and elements
    fixed = gtk_fixed_new();
    
    GError* err = NULL;
    loopbtn = gtk_button_new();
    GdkPixbuf *looppixbuf = gdk_pixbuf_new_from_file_at_size(loop_image_dir.c_str(), mic_image_size, mic_image_size, &err);
    if(err!=NULL) return;
    gtk_button_set_image(GTK_BUTTON(loopbtn), gtk_image_new_from_pixbuf(looppixbuf));
    gtk_widget_set_size_request(loopbtn, mic_image_size, mic_image_size);
    gtk_fixed_put(GTK_FIXED(fixed), loopbtn, 0, 0);
    g_signal_connect(G_OBJECT(loopbtn), "clicked", G_CALLBACK(loopbtn_Click), NULL);
    
    unloopbtn = gtk_button_new();
    GdkPixbuf *unlooppixbuf = gdk_pixbuf_new_from_file_at_size(unloop_image_dir.c_str(), mic_image_size, mic_image_size, &err);
    if(err!=NULL) return;
    gtk_button_set_image(GTK_BUTTON(unloopbtn), gtk_image_new_from_pixbuf(unlooppixbuf));
    gtk_widget_set_size_request(unloopbtn, mic_image_size, mic_image_size);
    gtk_fixed_put(GTK_FIXED(fixed), unloopbtn, 0, 0);
    g_signal_connect(G_OBJECT(unloopbtn), "clicked", G_CALLBACK(unloopbtn_Click), NULL);
    
    gtk_container_add(GTK_CONTAINER(window), fixed); 
    
    // show window
    gtk_widget_show_all(window);
    
    // check if loopback running outside
    is_looping = search_pa_loopback();
    if(is_looping)
        gtk_widget_hide(unloopbtn);
    else
        gtk_widget_hide(loopbtn);
}

void main_restore_then_quit(){
    if(is_looping){
        unload_pa_loopback();
    }
    
    gtk_main_quit();
}

int main(int argc, char *argv[]) { 
    gtk_init(&argc, &argv);
    buildWindow();
    g_signal_connect(window, "destroy", G_CALLBACK(main_restore_then_quit), NULL);
    gtk_main();
    
    return 0;
}


