/*
 * returns < 0 for unsuccessful connect, fd for ok
 *
 */
static int complete_connection(int slot)
{
        int retval;
        struct sockaddr_atmsvc dummy;

        dprintf("mpcd: io.c: complete_connection() completing fd %d slot %d\n", fds[slot].fd, slot);
        /* this seems to be common method in Linux-ATM
         * making sure that nonblocking connect was
         * completed successfully
         */
        retval = connect(fds[slot].fd,(struct sockaddr *)&dummy, sizeof(dummy));
        if (retval < 0) {
                printf("mpcd: io.c: complete_connection(): '%s'\n", strerror(errno));
                socket_type[slot] = NOT_USED;
                update_ingress_entry(NULL, fds[slot].fd, INGRESS_NOT_USED);
                close(fds[slot].fd);
                fds[slot].fd = -1;
                fds[slot].revents = 0;
                return 0;
        }
        socket_type[slot] &= ~CONNECTING;
        socket_type[slot] |= CONNECTED;
        
        fds[slot].events  = POLLIN; /* We left POLLOUT accidentally in. Hope you never do the same */
        fds[slot].revents = 0;
        if(socket_type[slot] & OUTGOING_SHORTCUT)
                return add_shortcut(slot, MPC_SOCKET_INGRESS);
        return fds[slot].fd;
}
    add_loadfile( "projectm-title-font", FONT_PATH,
                  TITLE_FONT_TXT, TITLE_FONT_LONGTXT, true )
    add_loadfile( "projectm-menu-font", FONT_PATH_MENU,
                  MENU_FONT_TXT, MENU_FONT_LONGTXT, true )
#endif
    add_integer( "projectm-width", 800, WIDTH_TEXT, WIDTH_LONGTEXT,
                 false )
    add_integer( "projectm-height", 640, HEIGHT_TEXT, HEIGHT_LONGTEXT,
                 false )
    add_integer( "projectm-meshx", 32, MESHX_TEXT, MESHX_LONGTEXT,
                 false )
    add_integer( "projectm-meshy", 24, MESHY_TEXT, MESHY_LONGTEXT,
                 false )
    add_integer( "projectm-texture-size", 1024, TEXTURE_TEXT, TEXTURE_LONGTEXT,
                 false )
    add_shortcut( "projectm" )
    set_callbacks( Open, Close )
vlc_module_end ()


/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
struct filter_sys_t
{
    /* */
    vlc_thread_t thread;
    vlc_sem_t    ready;
    bool         b_error;

    /* Opengl */
void Pgr_linear<G>::doContraction(G &graph) {
    std::ostringstream contraction_debug;
    contraction_debug << "Performing contraction\n";
    std::priority_queue<V, std::vector<V>, std::greater<V> > linearPriority;
    for (const auto linearVertex : linearVertices) {
        linearPriority.push(linearVertex);
    }
    contraction_debug << "Linear vertices" << std::endl;
    for (const auto v : linearVertices) {
        contraction_debug << graph[v].id << ", ";
    }
    contraction_debug << std::endl;
    while (!linearPriority.empty()) {
        V current_vertex = linearPriority.top();
        linearPriority.pop();
        if (!is_linear(graph, current_vertex)) {
            linearVertices -= current_vertex;
            continue;
        }
        Identifiers<V> adjacent_vertices =
            graph.find_adjacent_vertices(current_vertex);
        pgassert(adjacent_vertices.size() == 2);

        V vertex_1 = adjacent_vertices.front();
        adjacent_vertices.pop_front();
        V vertex_2 = adjacent_vertices.front();
        adjacent_vertices.pop_front();

        contraction_debug << "Adjacent vertices\n";
        contraction_debug << graph[vertex_1].id
            << ", " << graph[vertex_2].id
            << std::endl;

        if (graph.m_gType == DIRECTED) {
            if (graph.out_degree_to_vertex(vertex_1, current_vertex) > 0 &&
                    graph.in_degree_from_vertex(vertex_2, current_vertex) > 0) {
                E e1 = graph.get_min_cost_edge(vertex_1,
                        current_vertex);
                E e2 = graph.get_min_cost_edge(current_vertex,
                        vertex_2);
                add_shortcut(graph, current_vertex, e1, e2);
            }

            if (graph.out_degree_to_vertex(vertex_2, current_vertex) > 0 &&
                    graph.in_degree_from_vertex(vertex_1, current_vertex) > 0) {
                E e1 = graph.get_min_cost_edge(vertex_2,
                        current_vertex);
                E e2 = graph.get_min_cost_edge(current_vertex,
                        vertex_1);
                add_shortcut(graph, current_vertex, e1, e2);
            }
        } else if (graph.m_gType == UNDIRECTED) {
            if (graph.out_degree_to_vertex(vertex_1, current_vertex) > 0 &&
                    graph.in_degree_from_vertex(vertex_2, current_vertex) > 0) {
                contraction_debug << "UNDIRECTED graph before contraction\n";
                graph.print_graph(contraction_debug);
                E e1 = graph.get_min_cost_edge(vertex_1,
                        current_vertex);
                E e2 = graph.get_min_cost_edge(current_vertex,
                        vertex_2);
                add_shortcut(graph, current_vertex, e1, e2);
            }
        }

        graph.disconnect_vertex(current_vertex);
        linearVertices -= current_vertex;
        if (is_linear(graph, vertex_1)
                && !forbiddenVertices.has(vertex_1)) {
            linearPriority.push(vertex_1);
            linearVertices += vertex_1;
        }
        if (is_linear(graph, vertex_2)
                && !forbiddenVertices.has(vertex_2)) {
            linearPriority.push(vertex_2);
            linearVertices += vertex_2;
        }
    }
    debug << contraction_debug.str().c_str() << "\n";
}
void main_loop(int listen_socket)
{
        int i, changed_fds;
        int kernel_ok, mps_ok, new_ctrl, new_shortcut;
        int poll_timeout = POLL_TIMEOUT;
        time_t now, previous_now;
	for (i = 0; i < OPEN_MAX; i++)
                fds[i].fd = -1;

        fds[0].fd     = mpc_control.kernel_socket;     /* mpcd <--> kernel socket   */
        fds[0].events = POLLIN;
        socket_type[0]= KERNEL;

	if(!mpc_control.mps_ctrl_addr_set)             /* Can't do much without the MPS control ATM addr */
	        wait_for_mps_ctrl_addr();
	connect_to_MPS();
	
        fds[1].fd     = mpc_control.MPS_socket;        /* we opened this to MPS      */
        fds[1].events = POLLIN;
        socket_type[1]= (OUTGOING_CTRL | CONNECTED);
        fds[2].fd     = mpc_control.MPS_listen_socket; /* for incoming control calls */
        fds[2].events = POLLIN;
        socket_type[2]= LISTENING_CTRL;
        fds[3].fd     = listen_socket;     /* for incoming shortcuts     */
        fds[3].events = POLLIN;
        socket_type[3]= LISTENING_DATA;
        fds_used = first_empty = 4;
        now = previous_now = time(NULL);

        while (1) {
                kernel_ok = mps_ok = new_ctrl = new_shortcut = 1;
                fflush(stdout);
#ifdef BROKEN_POLL
                changed_fds = poll2select(fds, fds_used, poll_timeout);
#else
                changed_fds = poll(fds, fds_used, poll_timeout);
#endif
#if 0
                printf("\nio.c: main_loop() poll returns %d\n", changed_fds);
                for (i = 0; i < OPEN_MAX; i++) {
                        if (fds[i].fd < 0 ) continue;    /* slot not in use */
                        if ( fds[i].revents == 0) {
                                printf("check1: fd %d slot %d not changed\n", fds[i].fd, i);
                        }
                        else printf("check1: fd %d slot %d     changed\n", fds[i].fd, i);
                }
#endif

                switch(changed_fds) {
                case -1:
                        printf("mpcd: io.c: main_loop: poll error: %s\n", strerror(errno));
			if(errno == EINTR) continue;
                        goto out; /* return to main() */
                        break; /* not reached */
                case 0:
			keep_alive_sm(0, -1);  /* (keepalive_liftime, seq_num) */
                        clear_expired(); /* id_list.c */
			poll_timeout = POLL_TIMEOUT;
                        previous_now = time(NULL);
                        continue;
                        break; /* not reached */
                }

                /* It was not a timeout. Adjust poll_timeout */
                now = time(NULL);
                poll_timeout -= now - previous_now;
                if (poll_timeout < 0) poll_timeout = 0;

                /* Since we are here something happened to the fds */
                if (fds[0].revents) {
                        dprintf("mpcd: io.c: main_loop() msg_from_kernel\n");
                        kernel_ok = msg_from_kernel(fds[0].fd);
                        changed_fds--;
                }
                if (fds[1].revents) {
                        ddprintf("mpcd: io.c: main_loop() msg_from_mps1\n");
                        mps_ok = msg_from_mps(1);
                        changed_fds--;
                }
                if (fds[2].revents) {
                        new_ctrl = accept_conn(2);
			changed_fds--;
			if( new_ctrl < 0 )
			        break;
			socket_type[new_ctrl] = INCOMING_CTRL | CONNECTED;
                        dprintf("mpcd: io.c main_loop() accepted INCOMING_CTRL slot %d\n", new_ctrl);
		}
                if (fds[3].revents) {
                        new_shortcut = accept_conn(3);
                        dprintf("mpcd: io.c main_loop() accepted INCOMING_SHORTCUT slot %d\n", new_shortcut);
			changed_fds--;
			if( new_shortcut < 0 )
			        break;
			socket_type[new_shortcut] = INCOMING_SHORTCUT;
                        if (add_shortcut(new_shortcut, MPC_SOCKET_EGRESS) < 0)
                                break;
		}

#if 0
                if (changed_fds == 0)  /* see if we can already go back to poll() */
                        continue;
#endif

                for (i = first_empty; i < fds_used; i++) {
                        if (fds[i].fd < 0 ) continue;    /* slot not in use */
                        if ( fds[i].revents == 0) {
                                ddprintf("fd %d slot %d not changed\n", fds[i].fd, i);
                                continue;
                        }
                        ddprintf("about to process fd %d slot %d\n", fds[i].fd, i);
                        if (socket_type[i] & INCOMING_CTRL) {
                                ddprintf("mpcd: io.c: main_loop() msg_from_mps2\n");
                                mps_ok = msg_from_mps(i);
                        }
                        else {
                                ddprintf("mpcd: io.c: main_loop() checking connection fd %d\n", fds[i].fd);
                                if (check_connection(i) < 0) {
                                        printf("mpcd: io.c: main_loop: check_connection returned < 0\n");
                                        break; /* this will cause break from while(1) too */
                                }
                        }
			if (--changed_fds == 0) break; /* no more changed fds, leave for() */
                }

                if (changed_fds != 0){
			printf("mpcd: changed_fds = %d\n", changed_fds);
                        /* break; */         /* leave while(1) */
		}
                if (kernel_ok && mps_ok >= 0 && new_ctrl >= 0 && new_shortcut >= 0)
		        continue; /* back to poll() */
                else break;       /* leave main_loop */
        }
        
 out:
        /* clean up, close the sockets */
        for (i = 0; i < fds_used; i++) {
                if (fds[i].fd < 0)
		        continue;
                close(fds[i].fd);
                socket_type[i] = NOT_USED;
        }
        printf("mpcd: io.c: exiting main_loop()\n");

        return;
}