#include<cmath>
#include<fstream>
#include<iostream>
#include<vector>
#include<cstdlib>
#include "tnode.h"
#include<map>
using namespace std;
map<int,bool> errors;
vector<vector<int> > circuit;
vector<vector<int> > circuit_old;
vector<vector<int> > transistorids;
int ptransistors,ntransistors;
int circuit_width, circuit_height;
int number_of_ptransistors, number_of_ntransistors;
int number_of_outputs, number_of_inputs;
int number_of_vdds, number_of_vccs;
    int inputgroups;
    vector<vector<int> > groups;
    int outputgroups;
    int n;
    vector<vector<int> > ogroups;
    int weaks;
    vector<int> weaksx;
    vector<int> weaksy;
int no_e;
bool toss(float prob) {
    int r=rand();
    return (1.0*r*1.0/RAND_MAX<=prob);
    
}


int get_node_type(int type) {
    if(type==0) return NODE_TYPE_EMPTY;
    if(type==1) return NODE_TYPE_TRANSISTOR_P;
    if(type==2) return NODE_TYPE_TRANSISTOR_N;
    if(type<15) return NODE_TYPE_JUNCTION;
    int prev=15;
    if(type>=prev && type < prev + number_of_outputs) return NODE_TYPE_OUTPUT;
    prev += number_of_outputs;
    if( type >= prev && type < prev + number_of_inputs) return NODE_TYPE_INPUT;
    prev += number_of_inputs;
    if( type >= prev && type < prev + number_of_vdds) return NODE_TYPE_VDD;
    prev += number_of_vdds;
    if( type >= prev && type < prev + number_of_vccs) return NODE_TYPE_VCC;
    prev += number_of_vccs;
    if( type >= prev && type < prev + number_of_ptransistors) return NODE_TYPE_TRANSISTOR_P;
    prev += number_of_ptransistors;
    if( type >= prev && type < prev + number_of_ntransistors) return NODE_TYPE_TRANSISTOR_N;
    return NODE_TYPE_UNKNOWN;
}
void read_input(char* file) {
    ifstream fin(file);
    // reading attributes
    fin>>circuit_height>>circuit_width;
    fin>>number_of_outputs>>number_of_inputs;
    fin>>number_of_vdds>>number_of_vccs;
    fin>>number_of_ptransistors>>number_of_ntransistors;

    //initializing circuit grid
    circuit.resize(circuit_height);
    circuit_old.resize(circuit_height);
    transistorids.resize(circuit_height);
    for(int i=0;i<circuit_height;i++) {
    	circuit[i].resize(circuit_width);
    	circuit_old[i].resize(circuit_width);
    	transistorids[i].resize(circuit_width);
    }

    //reading circuit grid
    for(int i=0;i<circuit_height;i++) {
        for(int j=0;j<circuit_width;j++) {
            fin >> circuit[i][j];
            circuit_old[i][j]=circuit[i][j];
            transistorids[i][j]=0;
            if(get_node_type(circuit[i][j])==NODE_TYPE_TRANSISTOR_P) {
                transistorids[i][j]=circuit[i][j]-14-number_of_outputs-number_of_inputs-number_of_vdds-number_of_vccs;
                circuit[i][j]=1;
            } else if(get_node_type(circuit[i][j])==NODE_TYPE_TRANSISTOR_N) {
                transistorids[i][j]=circuit[i][j]-14-number_of_outputs-number_of_inputs-number_of_vdds-number_of_vccs-number_of_ptransistors;
                circuit[i][j]=2;
                
            }
        }
    }
    fin>>outputgroups;
    ogroups.resize(outputgroups);
    for(int i=0;i<outputgroups;i++) {
        fin>>n;
        ogroups[i].resize(n);
        for(int j=0;j<n;j++) fin>>ogroups[i][j];
    }
    fin>>inputgroups;
    groups.resize(inputgroups);
    for(int i=0;i<inputgroups;i++) {
        fin>>n;
        groups[i].resize(n);
        for(int j=0;j<n;j++) fin>>groups[i][j];
    }
    if(!fin.eof()) {
        fin>>weaks;
        weaksx.resize(weaks);
        weaksy.resize(weaks);
        for(int i=0;i<weaks;i++) {
        	int tr;
        	fin>>tr;
        	for(int j=0;j<circuit_height;j++) {
                for(int k=0;k<circuit_width;k++) {
                    if(circuit_old[j][k]==tr) {weaksx[i]=j;weaksy[i]=k;}
                }
            }

        }
    }
}
int counter=0;
void mutate(float prob) {
	for(int i=0;i<no_e;i++) {
	    int x = rand()%(circuit_width-2);
	    int y=rand()%(circuit_height-2);
	    x++;y++;
	    errors[y*circuit_width+x]=true;
    }
    for(int i=1;i<circuit_height-1;i++) {
    	for(int j=1;j<circuit_width-1;j++) {
    		if(!toss(prob)) continue;
            counter++;
            //if(errors.count(i*circuit_width+j)==0) continue;
    		int type=circuit[i][j];
    	    int newtype=0;
 /*   	    if(type!=1&&type!=2)
    	    while(newtype==type) {
                newtype=rand()%15;
            }
            else newtype=0;*/

            //if(circuit[i][j]==1) number_of_ptransistors--;
            // if(circuit[i][j]==2) number_of_ntransistors--;
            if(newtype==1) {
            	number_of_ptransistors++;
            	transistorids[i][j]=number_of_ptransistors;
            }
            else if(newtype==2) {
            	number_of_ntransistors++;
                transistorids[i][j]=number_of_ntransistors;
            }
    		circuit[i][j]=newtype;
            
        }
    }
    
}

void fix_ids() {

    for(int i=0;i<circuit_height;i++) {
    	for(int j=0;j<circuit_width;j++) {
            if(circuit[i][j]==1) {
                circuit[i][j]=transistorids[i][j]+14+number_of_outputs+number_of_inputs+number_of_vdds+number_of_vccs;
            } else if(circuit[i][j]==2) {
                circuit[i][j]=transistorids[i][j]+14+number_of_outputs+number_of_inputs+number_of_vdds+number_of_vccs+number_of_ptransistors;
            }
        }
    }
}

void print_output() {
    cout<<circuit_height<<" "<<circuit_width<<" ";
    cout<<number_of_outputs<<" "<<number_of_inputs<<" ";
    cout<<number_of_vdds<<" "<<number_of_vccs<<" ";
    cout<<number_of_ptransistors <<" "<<number_of_ntransistors <<"\n";
    for(int i=0;i<circuit_height;i++) { for(int j=0;j<circuit_width;j++) cout<<circuit[i][j]<<"\t"; cout<<endl;}
    cout<<outputgroups<<endl;
    for(int i=0;i<outputgroups;i++) {
        cout<<ogroups[i].size()<<" ";
        for(int j=0;j<ogroups[i].size();j++) cout<<ogroups[i][j]<<" ";
        cout<<endl;
    }
    cout<<inputgroups<<endl;
    for(int i=0;i<inputgroups;i++) {
        cout<<groups[i].size()<<" ";
        for(int j=0;j<groups[i].size();j++) cout<<groups[i][j]<<" ";
        cout<<endl;
    }
    if(weaks>0) {
        cout<<weaks<<endl;
        for(int j=0;j<weaks;j++) cout<<circuit[weaksx[j]][weaksy[j]]<<" ";
        cout<<endl;
    }
}


int main(int argc, char* argv[]) {
    read_input(argv[1]);
    float f=atof(argv[2]);
    int rnd=atoi(argv[3]);
    //no_e=atoi(argv[4]);
  //  no_e=1;
    srand(rnd);
    
    mutate(f);


 //   print_output();
//    cout<<"--\n";
    fix_ids();
    print_output();
    ofstream ffhj("data",fstream::app);
    ffhj<<counter<<endl;
}
