//
//  RepetitionRegion.m
//  ArcParser
//
//  Created by pia palme on 5/14/07.
//  Copyright 2007 __MyCompanyName__. All rights reserved.
//

#import "RepetitionRegion.h"

NSString *fundamentalSubstring;
NSRange range;						//range from the beginning to the very end

@implementation RepetitionRegion

- (id)initWithFundamentalSubstring:(NSString *)aFundamentalSubstring fromIndex:(int)rangeStart withLength:(int)rangeLength
{
	[super init];
	
	fundamentalSubstring = aFundamentalSubstring;
	
	//do fundamentalSubstring and length match?
	if (rangeLength % [fundamentalSubstring length] != 0)
	{
		return nil;
	}
	
	range = NSMakeRange(rangeStart, rangeLength);
	
	return self;
}

- (id)initWithFundamentalSubstring:(NSString *)aFundamentalSubstring inRange:(NSRange)aRange
{
	[super init];
	
	fundamentalSubstring = aFundamentalSubstring;
	
	//do fundamentalSubstring and length match?
	if (aRange.length % [fundamentalSubstring length] != 0)
	{
		return nil;
	}
	
	range = aRange;
	
	return self;
}

- (NSString *)fundamentalSubstring
{	
	return fundamentalSubstring;
}

- (NSString *)completeString
{
	if (fundamentalSubstring != nil)
	{
		NSMutableString* completeString = [[NSMutableString alloc] initWithCapacity:(int)range.length];
		
		int steps = (range.length / [fundamentalSubstring length]);
		int i = 0;
		for (i; i < steps; i++)
		{
			[completeString appendString:fundamentalSubstring];
		}
		
		return completeString;
	}
	else
	{
		return nil;
	}
}

- (NSRange)range
{
	return range;
}

- (int)repetitions
{
	return range.length / [fundamentalSubstring length];
}

- (int)startLocation
{
	return range.location;
}

//complete length
- (int)length
{
	return range.length;
}

- (BOOL)containsRangeFrom:(RepetitionRegion *)aRepetitionRegion
{
	NSRange aRange = [aRepetitionRegion range];
	
	//self contains location?
	if (aRange.location < (NSMaxRange(range) - 2) && (aRange.location > range.location))
	{
		//self contains location + length
		if ((NSMaxRange(aRange) - 1) <= NSMaxRange(range))
		{
			return YES;
		}
	}
	
	return NO;
}

- (BOOL)fundamentalSubstringContainsRangeFrom:(RepetitionRegion *)aRepetitionRegion
{
	NSRange aRange = [aRepetitionRegion range];
	NSRange firstFundamentalSubstringRange = NSMakeRange(range.location, [fundamentalSubstring length]);

	//fundamentalSubstring contains location?
	if (NSLocationInRange([aRepetitionRegion startLocation], firstFundamentalSubstringRange))
	{
		//fundamentalSubstring contains ending?
		if (NSLocationInRange((NSMaxRange(aRange) - 1), firstFundamentalSubstringRange))
		{
			return YES;
		}
	}
	
	return NO;
}

//Careful: cc111cc111cc[11111] -> NO (because needs to be split)
- (BOOL)repetitionRegionStartingInLastRepetition:(RepetitionRegion *)aRepetitionRegion
{
	if (NSLocationInRange([aRepetitionRegion range].location, NSMakeRange(NSMaxRange(range) - [fundamentalSubstring length], [fundamentalSubstring length])))
	{
		if ((NSIntersectionRange(range, [aRepetitionRegion range]).length % [[aRepetitionRegion fundamentalSubstring] length] == 0) && (NSIntersectionRange(range, [aRepetitionRegion range]).length / [[aRepetitionRegion fundamentalSubstring] length] > 1))
		{
			return NO;
		}
		else
		{
			return YES;
		}
	}
	
	return NO;
}

//eg. 1000110001 contains 11 intersecting
- (BOOL)containsIntersectingRangeFrom:(RepetitionRegion *)aRepetitionRegion
{
	NSRange firstFundamentalSubstringRange = NSMakeRange(range.location , [fundamentalSubstring length]);
	NSRange aRange = [aRepetitionRegion range];
	
	if (NSLocationInRange(aRange.location, firstFundamentalSubstringRange))
	{
		if (NSLocationInRange((NSMaxRange(aRange) - 1), firstFundamentalSubstringRange))
		{
			return NO;
		}
		else
		{
			return YES;
		}
	}
	
	return NO;
}

- (BOOL)overlappedByRangeFrom:(RepetitionRegion *)aRepetitionRegion
{
	NSRange aRange = [aRepetitionRegion range];
	
	if (NSLocationInRange(aRange.location, range) && !NSLocationInRange((NSMaxRange(aRange) - 1), range))
	{
		return YES;
	}
	
	return NO;
}

//returns nil if splitting is not possible
//
//eg. faff,faff,faff
- (NSArray *)splitIntersectingRepetitionRegion:(RepetitionRegion *)aRepetitionRegion
{
	NSMutableArray *splittedRepetitionRegions = nil;
	RepetitionRegion *splittedRepetitionRegion = nil;
	NSRange firstFundamentalSubstringRange = NSMakeRange(0 , [fundamentalSubstring length]);
	NSRange secondFundamentalSubstringRange = NSMakeRange(([fundamentalSubstring length] - 1) , [fundamentalSubstring length]);
	NSRange aRange = [aRepetitionRegion range];
	NSRange toSplitRange;
	NSRange splittedRange;
	BOOL follower = NO;
	
	//look if aRepetitionRegion is a follower eg. abbaabb[aa]bba
	if (!NSLocationInRange(aRange.location, firstFundamentalSubstringRange))
	{
		if (NSEqualRanges(NSIntersectionRange(aRange, range), aRange))
		{
			follower = YES;
			toSplitRange = NSMakeRange(aRange.location % [fundamentalSubstring length], aRange.length);
		}
	}
	else
	{
		toSplitRange = aRange;
	}
	
	//start location fits
	if (NSLocationInRange(toSplitRange.location, firstFundamentalSubstringRange))
	{
		//range is in the second repetition
		if (NSLocationInRange((NSMaxRange(toSplitRange) - 1), secondFundamentalSubstringRange))
		{
			int firstTokenLength = NSMaxRange(firstFundamentalSubstringRange) - toSplitRange.location;
			int secondTokenLength = NSMaxRange(toSplitRange) - NSMaxRange(firstFundamentalSubstringRange);
			
			if (firstTokenLength % [[aRepetitionRegion fundamentalSubstring] length] == 0)
			{
				//eg. a1aa,a1aa
				if (firstTokenLength / [[aRepetitionRegion fundamentalSubstring] length] > 1)
				{
					splittedRepetitionRegions = [NSMutableArray arrayWithCapacity:2];
				
					//splitedRange.location same for follower or not
					splittedRange = NSMakeRange(aRange.location, firstTokenLength);
					
					splittedRepetitionRegion = [[RepetitionRegion alloc] initWithFundamentalSubstring:[aRepetitionRegion fundamentalSubstring] inRange:splittedRange];
					[splittedRepetitionRegions addObject:splittedRepetitionRegion];
				}
			}
			
			if (secondTokenLength % [[aRepetitionRegion fundamentalSubstring] length] == 0)
			{
				//eg. aa1a,aa1aa
				if (secondTokenLength / [[aRepetitionRegion fundamentalSubstring] length] > 1)
				{
					if (!splittedRepetitionRegions)
					{
						splittedRepetitionRegions = [NSMutableArray arrayWithCapacity:1];
					}
					
					if (follower)
					{
						splittedRange = NSMakeRange((NSMaxRange(aRange) / [fundamentalSubstring length]) * [fundamentalSubstring length], secondTokenLength);
					}
					else
					{
						splittedRange = NSMakeRange(NSMaxRange(firstFundamentalSubstringRange), secondTokenLength);
					}
					
					splittedRepetitionRegion = [[RepetitionRegion alloc] initWithFundamentalSubstring:[aRepetitionRegion fundamentalSubstring] inRange:splittedRange];
					[splittedRepetitionRegions addObject:splittedRepetitionRegion];
				}
			}
		}
	}
	
	return splittedRepetitionRegions;
}


//c[bb]baba
- (NSArray *)splitOnIndex:(int)index
{
	NSMutableArray *splittedRepetitionRegions = nil;
	NSRange firstRange;
	NSRange secondRange;
	
	if (NSLocationInRange(index, range))
	{
		firstRange = NSMakeRange(range.location, index - range.location);
		secondRange = NSMakeRange(index, range.length - firstRange.length);
		
		//first region is ok
		if (firstRange.length % [fundamentalSubstring length] == 0 && (firstRange.length / [fundamentalSubstring length] > 1))
		{
			splittedRepetitionRegions = [NSMutableArray arrayWithCapacity:2];
			[splittedRepetitionRegions addObject:[[RepetitionRegion alloc] initWithFundamentalSubstring:fundamentalSubstring inRange:firstRange]];
		}
		//second region is ok
		if ((secondRange.length % [fundamentalSubstring length] == 0) && (secondRange.length / [fundamentalSubstring length] > 1))
		{
			if (!splittedRepetitionRegions)
			{
				splittedRepetitionRegions = [NSMutableArray arrayWithCapacity:1];
			}
			[splittedRepetitionRegions addObject:[[RepetitionRegion alloc] initWithFundamentalSubstring:fundamentalSubstring inRange:secondRange]];
		}
	}
	
	return splittedRepetitionRegions;	
}

//in ab11ab[1111], 1111 trunkateWith: ab11 = 11 (depending on locations)
- (BOOL)trunkateWith:(RepetitionRegion *)aRepetitionRegion
{
	NSRange cuttingRange = [aRepetitionRegion range];
	NSRange trunkatedRange;
	
	//trunkate in the back
	if (NSLocationInRange(cuttingRange.location, range))
	{
		if ((NSIntersectionRange(range, cuttingRange).length % [fundamentalSubstring length] == 0) && (NSIntersectionRange(range, cuttingRange).length / [fundamentalSubstring length] > 1))
		{
			range = NSMakeRange(range.location, (range.length - NSIntersectionRange(range, cuttingRange).length));
			return YES;
		}
	}
	//trunkate in the front
	else if (cuttingRange.location < range.location)
	{	
		if (((range.length - NSIntersectionRange(range, cuttingRange).length) % [fundamentalSubstring length] == 0) && ((range.length - NSIntersectionRange(range, cuttingRange).length) / [fundamentalSubstring length] > 1))
		{
			range = NSMakeRange(NSMaxRange(cuttingRange), (range.length - NSIntersectionRange(range, cuttingRange).length));
			return YES;
		}
	}
	
	return NO;
}

- (BOOL)matchingPairIsConsecutiveFundamentalSubstring:(MatchingPair *)aMatchingPair
{
	if ([[aMatchingPair string] isEqualToString:fundamentalSubstring] && ([aMatchingPair distanceBetweenStrings] == 0))
	{
		if ((NSLocationInRange([aMatchingPair firstLocation], range)) && (NSLocationInRange(NSMaxRange([aMatchingPair secondRange]) -1, range)))
		{
			NSLog(@"consecutive");
			return YES;
		}
	}
	
	NSLog(@"not consecutive");
	return NO;
}

- (BOOL)containsMatchingPairInFundamentalSubstring:(MatchingPair *)aMatchingPair
{
	if ([aMatchingPair stringLength] < [fundamentalSubstring length])
	{
		NSRange firstFundamentalSubstringRange = NSMakeRange(range.location, [fundamentalSubstring length]);
		NSRange movedMatchingPairRange = NSMakeRange([aMatchingPair firstLocation] % [fundamentalSubstring length], NSMaxRange([aMatchingPair secondRange]) - [aMatchingPair firstLocation]);
		
		NSLog(@"%i, %i", movedMatchingPairRange.location, movedMatchingPairRange.length);
		
		if (NSIntersectionRange(movedMatchingPairRange, firstFundamentalSubstringRange).length == movedMatchingPairRange.length)
		{
			NSLog(@"contained");
			return YES;
		}
	}
	
	NSLog(@"not contained");
	return NO;
}

- (void)printToLog
{
	//add check for (range != nil)
	if (fundamentalSubstring != nil)
	{
		NSLog(@"RepetitionRange, fundamentalSubstring: '%@' from index: %i length: %i", fundamentalSubstring, range.location, range.length);
	}
	else
	{
		NSLog(@"RepetitionRange not properly initialised.");
	}
}

@end
