#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/io.h>
#include <stdlib.h>
#include <math.h>

#define Channel_Count 8

unsigned char Values[Channel_Count];
unsigned char Last_Output = 0;
unsigned char Input = 0;
unsigned char Input_Matrix[Channel_Count * Channel_Count];
unsigned char Input_Array[Channel_Count];
unsigned char Input_Channel = 0;

unsigned long stepper = 0;
unsigned long compare = 100;

unsigned char Step_1 = 25, Step_2 = 50, Step_3 = 40, Step_4 = 70, Step_1_Top = 100, Step_2_Top = 150, Which_Step = 0;

unsigned char Step_1_Max = 90;

unsigned char On_Off = 1;
unsigned long Off_Counter = 0, Off_Count = 500, On_Count = 300;

//unsigned char Ons[Channel_Count];
unsigned char Samples[Channel_Count];
unsigned char Start_Periods[] = {2, 4, 6, 8, 10, 12, 14, 16};
unsigned char Periods[] = {2, 4, 6, 8, 10, 12, 14, 16};
unsigned char OnOffs[8];
unsigned char Ons[Channel_Count];
unsigned char Offs[] = {2*4, 4*4, 6*4, 8*4, 10*4, 12*4, 14*4, 16*4};
unsigned char Counters[Channel_Count];
unsigned char Pattern[Channel_Count * 8];
unsigned char Channel_Pattern_Index[Channel_Count];
unsigned char Channel_Pattern_Count[Channel_Count];

int main()
{
	DDRD = 0;
	PORTD = 255;
	
	DDRB = (1 << PB0);
	PORTB = 0;
	
	unsigned char Channel;
	unsigned char Output = 0;
	
	rand();
	for (Channel = 0; Channel < Channel_Count; Channel++)
	{
		unsigned char Pattern_Index = 0;
		Channel_Pattern_Count[Channel] = rand() % 3 + 2;
		for (Pattern_Index = 0; Pattern_Index < Channel_Pattern_Count[Channel]; Pattern_Index++)
		{
			Pattern[Channel * 8 + Pattern_Index] = rand() % 2;
		}
		Ons[Channel] = (rand() % 4) * 25;
	}
	
	while (1)
	{
		// Input
		Input = PIND;
		
		// Input matrix
			Input_Array[Input_Channel] = 0;
		for (Channel = 0; Channel < Channel_Count; Channel++)
		{
			Input_Matrix[Channel * Channel_Count + Input_Channel] = !((Input >> Channel) % 2);
			Input_Matrix[Input_Channel * Channel_Count + Channel] = !((Input >> Channel) % 2);
			if (Channel != Input_Channel)
				Input_Array[Input_Channel] |= !((Input >> Channel) % 2);
		}
		Input_Channel = (Input_Channel + 1) % Channel_Count;
		PORTD = 255 ^ (1 << Input_Channel);
		DDRD = 0 | (1 << Input_Channel);
		/*
		if (Input_Array[2])
		{
							Step_1 = 10;
							Step_1_Max = (rand() % 20) + 80;
		}
		if (Input_Array[3])
		{
							Step_2 = 10;
		}
		if (Input_Array[4])
		{
							Step_2+= 57;
		}
		if (Input_Array[5])
		{
			On_Count = rand() % 2000;
			Off_Count = rand() % 2000;
			
//							Step_2+= 57;
		}
		*/
		
		/*
		stepper++;
			if (stepper > Step_1)
			{
				Output = !Output;
				stepper -= Step_1;
				Step_1--;
				if (Step_1 > Step_1_Max)
					Step_1 = Step_1_Max;
				Which_Step = (Which_Step + 1) % 3;
			}
			*/
		
		/*
		unsigned char Inner_Channel;
		for (Channel = 0; Channel < Channel_Count; Channel++)
		{
			for (Inner_Channel = 0; Inner_Channel < Channel_Count; Inner_Channel++)
			{
				if (Channel != Inner_Channel)
				{
					if (Input_Matrix[Channel * Channel_Count + Inner_Channel])
					{
						if (!(Channel % 3))
							Step_1++;
//						if (!(Channel % 5))
//							Step_2++;
//						if (!(Channel % 7))
//							Step_3++;
						compare = Channel * 1 + Inner_Channel * 8;
					}
				}
			}
		}
		*/
		
		for (Channel = 0; Channel < Channel_Count; Channel++)
		{
			if (Input_Array[Channel])
			{
				Samples[Channel]++;
				if (Samples[Channel] >= Periods[Channel])
				{
//					Periods[Channel]++;
//					if (Periods[Channel] >= 50)
//						Periods[Channel] = Start_Periods[Channel];
					Samples[Channel] = 0;
					
					Counters[Channel]++;
					if (Pattern[Channel * 8 + Channel_Pattern_Index[Channel]])
						Output = !Output;
					if (Counters[Channel] >= Ons[Channel])
					{
						Periods[Channel]+= Start_Periods[Channel] / 5;
//						if (Periods[Channel] == 0)
//							Periods[Channel] = Start_Periods[Channel];

						Channel_Pattern_Index[Channel] = (Channel_Pattern_Index[Channel] + 1) % Channel_Pattern_Count[Channel];
						Counters[Channel] = 0;
//						OnOffs[Channel] = !OnOffs[Channel];
//						Ons[Channel] = rand() % 200;
					}
				}
			}
		}
		
		
		// Output
		PORTB = Output;
	}
	
	return 0;
}
