#include "BSprivate.h"

/*+ BSorig_inode - Change the inode structure to include the original,
                   unpermuted i-node numbers

    Input Parameters:
.   A - the sparse matrix
.   procinfo - the usual processor stuff

    Output Parameters:
.   A - the sparse matrix changed to include the original i-node numbers

    Returns:
    void

 +*/
void BSorig_inode(BSpar_mat *A, BSprocinfo *procinfo)
{
	BMcomp_msg *to_msg, *from_msg;
	BMphase *phase_ptr, *to_phase, *from_phase;
	BMmsg *msg;
	int	i, j, k;
	int	cl_ind, tcl_ind, cur_proc, in_ind;
	int	count, size;
	int	last;
	int	*setup_data, *user_data;
	BScl_2_inode *clique2inode;
	BSnumbering *color2clique;
	BSinode *inodes;
	int	local_num;
	int	*msg_buf, *data_ptr, msg_len;
	int	*data, data_len, ind, *perm, *iperm;
	void (*map)(int,int *,int *,BSprocinfo *,BSmapping *);
	void (*lmap)(int,int *,int *,BSprocinfo *,BSmapping *);

	/* initialize communication structures */
	to_msg = BMcomp_init(COMP_MSG_BASE); CHKERR(0);
	from_msg = BMcomp_init(COMP_MSG_BASE); CHKERR(0);

	/* initialize variables for ease of use */
	map = A->map->fglobal2local;
	lmap = A->map->flocal2global;
	perm = A->perm->perm;
	iperm = A->inv_perm->perm;
	color2clique = A->color2clique;
	clique2inode = A->clique2inode;
	inodes = A->inodes->list;

	/* now go through and figure out everyone that we need stuff from */
	/* do it by color, where each color is a phase */
	for (i=0;i<color2clique->length-1;i++) {
		cl_ind = color2clique->numbers[i];
		while (cl_ind < color2clique->numbers[i+1]) {
			/* figure out the message size and destination */
			cur_proc = clique2inode->proc[cl_ind];
			tcl_ind = cl_ind;
			size = 0;
			while ((tcl_ind < color2clique->numbers[i+1]) && 
				(cur_proc == clique2inode->proc[tcl_ind])) {
				/* add in the lengths, nonlocals are negative */
				size += abs(clique2inode->d_mats[tcl_ind].size);
				tcl_ind++;
			}
			if (cur_proc != procinfo->my_id) {
				/* now we know the message size, allocate the message, etc */
				msg = BMcreate_msg(i,-1,MPI_INT,cur_proc); CHKERR(0);
				BMadd_msg(from_msg,msg,procinfo); CHKERR(0);
				MY_MALLOC(user_data,(int *),sizeof(int)*2,1);
				user_data[0] = cl_ind;
				user_data[1] = tcl_ind-1;
				BMset_user_data(msg,user_data,2,BSfree_comm_data);
				CHKERR(0);
				MY_MALLOC(setup_data,(int *),sizeof(int)*size,1);
				count = 0;
				while (count < size) {
					for (j=clique2inode->inode_index[cl_ind];
						j<clique2inode->inode_index[cl_ind+1];j++) {
						setup_data[count] = inodes[j].o_gcol_num[0];
						count++;
						for (k=1;k<inodes[j].num_cols;k++) {
							setup_data[count] = -1;
							count++;
						}
					}
					cl_ind++;
				}
				BMset_setup_data(msg,setup_data,size,BSfree_comm_data);
				CHKERR(0);
				BMset_msg_size(msg,size); CHKERR(0);
			} else {
				/* take care of local numbering */
				for (cl_ind=cl_ind;cl_ind<tcl_ind;cl_ind++) {
					for (j=clique2inode->inode_index[cl_ind];
						j<clique2inode->inode_index[cl_ind+1];j++) {
						(*map)(1,&(inodes[j].o_gcol_num[0]),&ind,procinfo,
							A->map); CHKERR(0);
						last = perm[ind]+1;
						for (k=1;k<inodes[j].num_cols;k++) {
							local_num = iperm[last];
							(*lmap)(1,&local_num,&ind,procinfo,A->map);
							CHKERR(0);
							inodes[j].o_gcol_num[k] = ind;
							last++;
						}
					}
				}
			}
		}

		/* now, let's work out what I need to send */
		phase_ptr = BMget_phase(from_msg,i); CHKERR(0);
		count = BMfix_send(SETUP_ORIGINAL_MSG,COMP_MSG_BASE,MPI_INT,to_msg,
			phase_ptr,BSfree_comm_data,procinfo); CHKERR(0);
		
		/* now free up the setup data */
		msg = NULL;
		while ((msg = BMnext_msg(phase_ptr,msg)) != NULL) {
			CHKERR(0);
			BMfree_setup_data(msg);
			CHKERR(0);
		}
		CHKERR(0);
	}

	/* now, go over the messages that I have to send and translate the */
	/* user data */
	for (i=0;i<color2clique->length-1;i++) {
		phase_ptr = BMget_phase(to_msg,i); CHKERR(0);
		msg = NULL;
		while ((msg = BMnext_msg(phase_ptr,msg)) != NULL) {
			CHKERR(0);
			data = BMget_user(msg,&data_len);
			BMset_msg_size(msg,data_len); CHKERR(0);
			last = -1;
			for (j=0;j<data_len;j++) {
				if (data[j] < 0) { 
					local_num = iperm[last];
					(*lmap)(1,&local_num,&ind,procinfo,A->map); CHKERR(0);
					data[j] = ind;
					last++;
				} else {
					(*map)(1,&(data[j]),&ind,procinfo,A->map); CHKERR(0);
					last = perm[ind]+1;
				}
			}
		}
		CHKERR(0);
	}

	/* organize the messages */
	BMalloc_msg(to_msg); CHKERR(0);
	BMalloc_msg(from_msg); CHKERR(0);

	/* now send and receive the true info */
	BMinit_comp_msg(from_msg,procinfo); CHKERR(0);
	for (i=0;i<color2clique->length-1;i++) {
		/* send messages */
		to_phase = BMget_phase(to_msg,i); CHKERR(0);
		msg = NULL;
		while ((msg = BMnext_msg(to_phase,msg)) != NULL) {
			CHKERR(0);
			msg_buf = (int *) BMget_msg_ptr(msg); CHKERR(0);
			data_ptr = BMget_user(msg,&msg_len); CHKERR(0);
			for (j=0;j<msg_len;j++) {
				msg_buf[j] = data_ptr[j];
			}
			BMsendf_msg(msg,procinfo); CHKERR(0);
		}
		CHKERR(0);

		/* receive messages */
		from_phase = BMget_phase(from_msg,i); CHKERR(0);
		while ((msg = BMrecv_msg(from_phase)) != NULL) {
			CHKERR(0);
			msg_buf = (int *) BMget_msg_ptr(msg); CHKERR(0);
			data_ptr = BMget_user(msg,&msg_len); CHKERR(0);
			msg_len = BMget_msg_size(msg); CHKERR(0);
			count = 0;
			for (cl_ind=data_ptr[0];cl_ind<=data_ptr[1];cl_ind++) {
				for (in_ind=clique2inode->inode_index[cl_ind];
					in_ind<clique2inode->inode_index[cl_ind+1];in_ind++) {
					for (j=0;j<inodes[in_ind].num_cols;j++) {
						inodes[in_ind].o_gcol_num[j] = msg_buf[count];
						count++;
					}
				}
			}
			BMfree_msg(msg); CHKERR(0);
		}
		CHKERR(0);
	}

	/* clean up the message stuff */
	BMfinish_comp_msg(to_msg,procinfo); CHKERR(0);

	/* free up the message structure */
	BMfree_comp_msg(from_msg); CHKERR(0);
	BMfree_comp_msg(to_msg); CHKERR(0);
}


syntax highlighted by Code2HTML, v. 0.9.1