#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//Estrutura que representa os elementos da lista
typedef struct _no{
    int coeficiente;
    int *grau;
    struct _no *prox;
}*no;

no lista_vazia(void){
    //Cria um sentinela para facilitar os algoritmos de inserção e remoção
    no sentinela=(no)malloc(sizeof(struct _no));
    //Prox de sentinela aponta para nada
    sentinela->prox=NULL;
    return sentinela;
}

//Funcao para retornar a primeira posicao valida da lista
no inicio(no cabeca){
    return cabeca->prox;
}

//Funcao para retornar o endereco do proximo elemento da lista
no avancar(no lista){
    return lista->prox;
}

//Percorre a lista
no percorrer(no cabeca,int posicao){
    int i;
    //chama avança na lista a cada iteração
    for (i=0;i<posicao;i++){
        cabeca=avancar(cabeca);
    }
    return cabeca;
}

//Funcao para remover
int remover(int pos,no cabeca){
    no aux,aux2;
    aux=percorrer(cabeca,pos-1);
    if (aux->prox==NULL)
        return 0;
    aux2=avancar(aux);
    aux->prox=aux->prox->prox;
    free(aux2);
    return 1;
}

//Funcao para inserir apos um no da lista
void inserir_apos(no lista,int coeficiente,int *vetor,int tamanho_vetor){
    int i;
    //Aloca espaco para um novo no
    no novo=(no)malloc(sizeof(struct _no));
    //Aloca espaco para o vetor de inteiros dentro do no
    novo->grau=(int*)malloc(sizeof(int)*tamanho_vetor);
    
    //Prox de novo aponta para o proximo da lista atual
    novo->prox=lista->prox;
    //Novo recebe coeficiente
    novo->coeficiente=coeficiente;
    //Grau vai receber o vetor de inteiros
    for(i=0;i<tamanho_vetor;i++)
        novo->grau[i]=vetor[i];
    //Lista atual aponta para o novo no
    lista->prox=novo;
}
//Funcao para derivar um no da lista
void derivar(int var,no cabeca){
    //Contador
    int cont=0;
    //No temporario para nao modificar o valor de cabeca
    no tmp=cabeca;
    //Enquanto o no nao apontar para nulo
    while ((tmp=tmp->prox)!=NULL){
        //Incrementa o contador
        cont++;
        //Mutiplica o coeficiente pelo grau da variavel escolhida
        tmp->coeficiente=tmp->coeficiente*tmp->grau[var-1];
        //Decrementa o grau da variavel
        tmp->grau[var-1]--;
        //Se o coeficiente for igual a 0, retira o no da lista
        if(tmp->coeficiente==0){
            tmp=percorrer(cabeca,cont-1);
            remover(cont,cabeca);
            cont--;
        }
    }
}
//Funcao principal
int main(int argc,char **argv){
    if (argc!=2){
        printf("Digite na linha de comando o nome do arquivo a ser lido\n");
        exit(0);
    }
    
    char string[20];
    no cabeca=lista_vazia();
    no temp=cabeca;
    FILE *entrada,*saida;
    int num_var,*vetor,coeficiente,i,j,ordem;
    
    entrada=fopen(argv[1],"r");
    saida=fopen("pol.out","w");
    
    fscanf(entrada,"%d\n%s",&num_var,string);
    vetor=(int*)malloc(sizeof(int)*num_var);
    //Le os coeficientes e o grau das variáveis
    while(strcmp(string,"d")){
        coeficiente=atoi(string);
        for (i=0;i<num_var;i++) 
            fscanf(entrada,"%d",&vetor[i]);
        inserir_apos(temp,coeficiente,vetor,num_var);
        temp=avancar(temp);
        fscanf(entrada,"%s",string);
    }
    //ordem=(int*)malloc(sizeof(int)*num_var);
    fprintf(saida,"%d\n",num_var);
    i=0;
    //Iteração para ler do arquivo a ordem de derivação e faz a derivação
    while((fscanf(entrada,"%d\n",&ordem)) != EOF){
	i++;
	//Deriva
	derivar(ordem,cabeca);
	printf("\n%da. derivada em X%d:",i,ordem);
	//Vai para o inicio da lista
	temp=inicio(cabeca);
	//Iteração para escrever na tela os passos de derivação
	while(temp!=NULL){
		printf("%d",temp->coeficiente);
		for(j=0;j<num_var;j++){
			if (temp->grau[j]!=0)
				printf("x%d^%d",j+1,temp->grau[j]);
		}
		printf(" + ");
		temp=avancar(temp);
	}
   }
   printf("\n");
   //Vai para o inicio da lista
   temp=inicio(cabeca);
   //Escreve no arquivo a saida
   while(temp!=NULL){
        //Escreve no arquivo o coeficiente
		fprintf(saida,"%d\n",temp->coeficiente);
		//Escreve no arquivo o grau das variaveis
		for(j=0;j<num_var;j++){
			fprintf(saida,"%d ",temp->grau[j]);
		}
		fprintf(saida,"\n");
		//Vai para o proximo no da lista
		temp=avancar(temp);
   }
   //Fecha os arquivos
   fclose(entrada);
   fclose(saida);
   return 0;
}
