set fl [open exploit_regions.rpt w]

set site_matrix ""
set tmp ""
set open_locs_x ""
#delete_filler
set final_coords ""
delete_obj [get_db gui_rects -if {.gui_layer_name == *abcd*}]
delete_obj [get_db gui_rects -if {.gui_layer_name == *efgh*}]

set max_x 0
set min_x [get_db current_design .bbox.dx]
set max_y 0
set min_y [get_db current_design .bbox.dy]

foreach a [get_db insts $sc_inst_pattern] {
        if {[lindex [get_db $a .location] 0 0] < $min_x} {set min_x [lindex [get_db $a .location] 0 0]}
        if {[lindex [get_db $a .location] 0 0] > $max_x} {set max_x [lindex [get_db $a .location] 0 0]}
        if {[lindex [get_db $a .location] 0 1] < $min_y} {set min_y [lindex [get_db $a .location] 0 1]}
        if {[lindex [get_db $a .location] 0 1] > $max_y} {set max_y [lindex [get_db $a .location] 0 1]}
}
#set min_x [expr $min_x - 10]
#set max_x [expr $max_x + 10]
set crit_regs [get_db insts $sc_inst_pattern]
set tp [report_timing -from $crit_regs -collection ]
set slack [get_db $tp .slack]
set slack [expr $slack * 1000]

set slack_idx {14 22 40 72 120 236 420}
set load_idx {1 2 4 8 15 30 60}
set dist_idx {5 10 25 50 90 200 400}

for {set i 0} {$i < [expr [llength $slack_idx] - 1]} {incr i} {
	if {$slack >= [lindex $slack_idx $i] && $slack <  [lindex $slack_idx [expr $i + 1]]} {
	set diff1 [expr $slack - [lindex $slack_idx $i]]
	set diff2 [expr [lindex $slack_idx [expr $i + 1]] - $slack]
	if {$diff1 < [expr [expr 1.25 * [lindex $slack_idx $i]] - $slack]} {
		set dist [lindex $dist_idx $i]} elseif {
		$diff2 < [expr $slack - [expr 0.75 * [lindex $slack_idx [expr $i + 1]]]]} {set dist [lindex $dist_idx [expr $i + 1]]} else {
	set dist [expr ([lindex $dist_idx $i] + [lindex $dist_idx [expr $i + 1]])/2]}
	}
	if {$slack <= [lindex $slack_idx 0]} {set dist [lindex $dist_idx 0]}
	if {$slack >= [lindex $slack_idx end]} {set dist [lindex $dist_idx end]}
}

set key_rows "" 
set key_rows [get_obj_in_area -area [expr $min_x - $dist] [expr $min_y - $dist] [expr $max_x + $dist] [expr $max_y + $dist] -obj_type row]

set key_rows [lsort -u $key_rows]  
set key_rows_rect [get_db $key_rows .rect]

set rows_rect [get_db current_design .rows.rect.]
set sites_x [lindex [get_db sites .size] 0 0]
set sites_y [lindex [get_db sites .size] 0 1]
puts $fl "Empty Sites Per Row:"
puts $fl "Row Number\tNumber of Sites"
for {set i 0} {$i < [llength $rows_rect]} {incr i} {
	set curr_row [lindex $rows_rect $i]
	set curr_row_sites ""
	set start_x [lindex $curr_row 0]
	set end_x [lindex $curr_row 2]
	set low_y [lindex $curr_row 1]
	set high_y [lindex $curr_row 3]
	set open_count 0
	set curr_x $start_x
	for {set j $start_x} {$j < $end_x} {set j [expr $j + $sites_x]} {
		set next_x [expr $curr_x + $sites_x]
		set site_cell [get_obj_in_area -area [expr $curr_x + 0.1] [expr $low_y + 0.1] [expr $next_x - 0.1] [expr $high_y - 0.1] -obj_type inst]
		if {[llength $site_cell] == 0 || [regexp FILL $site_cell]} {
			if {[lsearch $key_rows_rect [lindex $rows_rect $i]] != -1} {
                              if {$curr_x > [expr $min_x - $dist] && $next_x < [expr $max_x + $dist]} {		
				incr open_count
				set tmp $curr_x
				lappend tmp $low_y
				lappend tmp $next_x
				lappend tmp $high_y
				lappend open_locs_x $tmp
				lappend curr_row_sites 1
				} else {lappend curr_row_sites 0}
			} else {
				lappend curr_row_sites 0
			}
		} else {
			lappend curr_row_sites 0
		}
		set curr_x $next_x
	}
	puts $fl "$i\t\t$open_count"
	lappend site_matrix $curr_row_sites
}
puts $fl "\n"	

array unset island_x_info
set island_x_count 0
set start_p 0
set end_p 0
for {set i 0} {$i < [llength $open_locs_x]} {incr i} {
	set adj_count 0
	set sites_in_island ""
	while {[lindex $open_locs_x $i 2] == [lindex $open_locs_x [expr $i + 1] 0]}  {
		if {$adj_count == 0} {
			set start_p [lindex $open_locs_x $i]
			lappend sites_in_island $i
		}           
		incr adj_count
		incr i
		set end_p [lindex $open_locs_x $i]
		lappend sites_in_island $i
	}
	incr adj_count                                               
#	if {$adj_count > 5} {puts $fl "$start_p -- $end_p -- $adj_count"}
	lappend island_x_info($island_x_count) $adj_count
	lappend island_x_info($island_x_count) $start_p
	lappend island_x_info($island_x_count) $end_p
	lappend island_x_info($island_x_count) $sites_in_island
	incr island_x_count
}
set connected_space_count 0
array unset connected_spaces
set open_locs_y $open_locs_x
for {set i 0} {$i < $island_x_count} {incr i} {
	set sp [lindex $island_x_info($i) 1]
	set ep [lindex $island_x_info($i) 2]
	set tmp_rect [lindex $sp 0]
	lappend tmp_rect [expr [lindex $sp 1] + $sites_y]
	lappend tmp_rect [lindex $sp 2]
	lappend tmp_rect [expr [lindex $sp 3] + $sites_y]
	set new_rect $tmp_rect
	if {[lsearch $open_locs_y $new_rect] > -1} {
		set pos [lsearch $open_locs_y $new_rect]
		for {set j 0} {$j < $island_x_count} {incr j} {                                        
			set new_ep [lsearch [lindex $island_x_info($j) 3] $pos]   
			if {$new_ep > -1} {                                
				set connected_spaces($connected_space_count) $i    
				lappend connected_spaces($connected_space_count) $j     
				incr connected_space_count
			}
		}
	} else {
		set new_rect [lreplace $new_rect 0 0 [lindex $ep 0]]
		set new_rect [lreplace $new_rect 2 2 [lindex $ep 2]]
		if {[lsearch $open_locs_y $new_rect] > -1} { 
                	set pos [lsearch $open_locs_y $new_rect]
                	for {set j 0} {$j < $island_x_count} {incr j} {        
                		set new_ep [lsearch [lindex $island_x_info($j) 3] $pos]   
                	        if {$new_ep > -1} {                                
                	                set connected_spaces($connected_space_count) $i          
                	                lappend connected_spaces($connected_space_count) $j
                	                incr connected_space_count
                	        }
                	}
        	}	
	}
}

array unset connected_spaces_final
set connected_spaces_count_final 0

for {set i 0} {$i < $connected_space_count} {incr i} {
	set flag 0
	for {set j 0} {$j < $connected_space_count} {incr j} {
		if {[lsearch $connected_spaces($j) [lindex $connected_spaces($i) 0]] > -1} {
			lappend connected_spaces_final($connected_spaces_count_final) [lindex $connected_spaces($i) 0]
			lappend connected_spaces_final($connected_spaces_count_final) [lindex $connected_spaces($i) 1]
			foreach w $connected_spaces($j) {
				lappend connected_spaces_final($connected_spaces_count_final) $w
				for {set k 0} {$k < $connected_space_count} {incr k} {
					if {[lsearch $connected_spaces($k) $w] > -1} {
						foreach q $connected_spaces($k) {lappend connected_spaces_final($connected_spaces_count_final) $q}
					}
				}
			}			
		}
		if {[lsearch $connected_spaces($j) [lindex $connected_spaces($i) 1]] > -1} {
			lappend connected_spaces_final($connected_spaces_count_final) [lindex $connected_spaces($i) $k]
			foreach w $connected_spaces($j) {
				lappend connected_spaces_final($connected_spaces_count_final) $w
				for {set k 0} {$k < $connected_space_count} {incr k} {
					if {[lsearch $connected_spaces($k) $w] > -1} {
						foreach q $connected_spaces($k) {lappend connected_spaces_final($connected_spaces_count_final) $q}
					}
				}
			}
		set flag 1
		}
	}
	if {$flag == 1} {
		set connected_spaces_final($connected_spaces_count_final) [lreplace [lsort -u $connected_spaces_final($connected_spaces_count_final)] 0 0]
		incr connected_spaces_count_final
	}
}

set unique_conn_count 1
array unset unique_conn


if {$connected_spaces_count_final > 0} {
	set unique_conn(0) $connected_spaces_final(0)
	for {set i 0} {$i < $connected_spaces_count_final} {incr i} {
		set flag 0
		for {set j 0} {$j < $i} {incr j} {
			if {[regexp $connected_spaces_final($j) $connected_spaces_final($i)]} {set flag 0;break} else {set flag 1}
		}
		if {$flag == 1} {set unique_conn($unique_conn_count) $connected_spaces_final($i); incr unique_conn_count}
	}
	
	set unique_flat ""
	set merged_final ""
	for {set i 0} {$i < $unique_conn_count} {incr i} {lappend unique_flat $unique_conn($i)}
	
	for {set i 0} {$i < [llength $unique_flat]} {incr i} {
		set conn_u [lindex $unique_flat $i]
		foreach a $unique_flat {
			foreach b $a {
				if {[lsearch [lindex $unique_flat $i] $b] > -1} {lappend conn_u $a}
			}
		}
		set conn_u_final ""
		foreach c $conn_u {
			if {[llength $c] == 1} {
			lappend conn_u_final $c
			} else {
				foreach d $c {lappend conn_u_final $d}
			}
		}
		lappend merged_final [lsort -r -u $conn_u_final]
	}
	
	array unset unique_merged_conn
	set merged_conn_count 1
	set unique_merged_conn(0) [lindex $merged_final 0]
	
	for {set i 0} {$i < $unique_conn_count} {incr i} {
	        set flag 0
	        for {set j 0} {$j < $i} {incr j} {
			if {[regexp [lindex $merged_final $j] [lindex $merged_final $i]]} {set flag 0;break} else {set flag 1}
		}
		if {$flag == 1} {set unique_merged_conn($merged_conn_count) [lindex $merged_final $i]; incr merged_conn_count}
	}
	
	array unset layer_info
	set max_signal_routing_layer 7
	
	#puts $fl "Number of Routes in region:"
	set num_count 0
	set final_island_count 0
	
	set max_route_count 0
	set total_free_count 0
	
	
	for {set i 0} {$i < $merged_conn_count} {incr i} {
		set site_islands ""
		set tmp_var ""
		foreach a $unique_merged_conn($i) {
			lappend tmp_var $a
			set tmp_var [lsort -r -u $tmp_var]
			foreach b [lindex $island_x_info($a) 3] {lappend site_islands $b}
		}
		if {[llength $site_islands] > $threshold} {
			set coordinates ""
			foreach c $site_islands {
				incr num_count
				lappend coordinates [lindex $open_locs_x $c]
			}
			lappend final_coords $coordinates
		}
	}			
}
for {set i 0} {$i < $island_x_count} {incr i} {
	if {$connected_spaces_count_final > 0} {
		if {[lsearch $tmp_var $i] == -1} {
			if {[llength [lindex $island_x_info($i) 3]] > $threshold} {
				set coordinates ""
#				incr final_island_count
				foreach c [lindex $island_x_info($i) 3] {
					lappend coordinates [lindex $open_locs_x $c]
#					create_gui_shape -layer abcd -rect [lindex $open_locs_x $c]
					incr num_count
				}
				#puts $fl "Open Region $final_island_count: [llength [lindex $island_x_info($i) 3]] Sites"
				#puts $fl "Sites:\n$coordinates\n\n"
				lappend final_coords $coordinates
			}
		}
	} else {
		if {[llength [lindex $island_x_info($i) 3]] > $threshold} {
			set coordinates ""
			foreach c [lindex $island_x_info($i) 3] {
				lappend coordinates [lindex $open_locs_x $c]
				incr num_count
			}
			lappend final_coords $coordinates
		}
	}
}

set all_matches ""
for {set i 0} {$i < [llength $final_coords]} {incr i} {
	set match_list ""
        foreach a [lindex $final_coords $i] {
        	for {set j 0} {$j < [llength $final_coords]} {incr j} {
        		set found_match [lsearch [lindex $final_coords $j] $a]
        		if {$found_match > -1} {lappend match_list $j}
        	}
	}
        set match_list [lsort -u $match_list]
        lappend all_matches $match_list
}

set all_matches [lsort -u $all_matches]
set final_site_count 0
set max_site_count 0

array unset track_value

foreach a [get_db track_patterns] {
	if {[get_db $a .layers.direction] == "vertical" && [get_db $a .direction] == "x"} {
		for {set i 1} {$i <= [get_db $a .num_tracks]} {incr i} {
			lappend track_value([get_db $a .layers.name]) [expr [get_db $a .start] + ([get_db $a .step]*$i)]
		}
	}
	if {[get_db $a .layers.direction] == "horizontal" && [get_db $a .direction] == "y"} {
		for {set i 1} {$i <= [get_db $a .num_tracks]} {incr i} {
			lappend track_value([get_db $a .layers.name]) [expr [get_db $a .start] + ([get_db $a .step]*$i)]
		}
	}
}

for {set i 0} {$i < [llength $all_matches]} {incr i} {
	puts $fl "Exploit Region [expr $i + 1]:"
	set site_coords ""
	foreach a [lindex $all_matches $i] {
		foreach b [lindex $final_coords $a] {
			lappend site_coords $b
			set site_coords [lsort -u $site_coords]
			create_gui_shape -layer abcd -rect $b
		}
	}
	foreach q [get_db layers -if {.type == *routing}] {
        	if {[get_db $q .route_index] < $max_signal_routing_layer} {set layer_count([get_db $q .name]) 0;set layer_info([get_db $q .name]) 0}
	}
	array unset route_tracks
	set route_tracks(metal1) ""
	set route_tracks(metal2) ""
	set route_tracks(metal3) ""
	set route_tracks(metal4) ""
	set route_tracks(metal5) ""
	set route_tracks(metal6) ""


	set reg_min_x [get_db current_design .bbox.dx]
	set reg_min_y [get_db current_design .bbox.dy]
	set reg_max_x 0
	set reg_max_y 0

	foreach d $site_coords {
		set routes [get_obj_in_area -area $d -obj_type {wire special_wire}]
		set filt_route [get_db $routes -if {.layer.route_index < $max_signal_routing_layer}]
		foreach w [get_db $filt_route] {
			if {[get_db $w .obj_type] == "wire"} { 
				if {[get_db $w .layer.route_index] == 1} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .points] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
				if {[get_db $w .layer.route_index] == 2} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .points] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
				if {[get_db $w .layer.route_index] == 3} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .points] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
				if {[get_db $w .layer.route_index] == 4} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .points] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
				if {[get_db $w .layer.route_index] == 5} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .points] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
				if {[get_db $w .layer.route_index] == 6} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .points] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
			} else {
				if {[get_db $w .layer.route_index] == 1} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .path] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
                                if {[get_db $w .layer.route_index] == 2} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .path] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
                                if {[get_db $w .layer.route_index] == 3} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .path] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
                                if {[get_db $w .layer.route_index] == 4} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .path] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
                                if {[get_db $w .layer.route_index] == 5} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .path] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
                                if {[get_db $w .layer.route_index] == 6} {lappend route_tracks([get_db $w .layer.name]) [lindex [get_db $w .path] 0 1]; set route_tracks([get_db $w .layer.name]) [lsort -u $route_tracks([get_db $w .layer.name])]}
			}
		}
		if {[lindex $d 0] < $reg_min_x} {set reg_min_x [lindex $d 0]}
		if {[lindex $d 1] < $reg_min_y} {set reg_min_y [lindex $d 1]}
		if {[lindex $d 2] > $reg_max_x} {set reg_max_x [lindex $d 2]}
		if {[lindex $d 3] > $reg_max_y} {set reg_max_y [lindex $d 3]}
	}

	foreach q [get_db layers -if {.type == *routing}] {
		if {[get_db $q .route_index] < $max_signal_routing_layer} {
			foreach w $route_tracks([get_db $q .name]) {if {[lsearch $track_value([get_db $q .name]) $w] > -1} {incr layer_count([get_db $q .name]))}}
			foreach w $track_value([get_db $q .name]) {
				if {[get_db $q .direction] == "horizontal"} {
					if {$w > $reg_min_y && $w < $reg_max_y} {incr layer_info([get_db $q .name])}
				}
				if {[get_db $q .direction] == "vertical"} {
					if {$w > $reg_min_x && $w < $reg_max_x} {incr layer_info([get_db $q .name])}
				}
			}
		}
	}	

	set route_count_1 [expr $layer_info(metal1) - $layer_count(metal1)]
	set route_count_2 [expr $layer_info(metal2) - $layer_count(metal2)]
	set route_count_3 [expr $layer_info(metal3) - $layer_count(metal3)]
	set route_count_4 [expr $layer_info(metal4) - $layer_count(metal4)]
	set route_count_5 [expr $layer_info(metal5) - $layer_count(metal5)]
	set route_count_6 [expr $layer_info(metal6) - $layer_count(metal6)]

	set total_route_count [expr $route_count_1 + $route_count_2 + $route_count_3 + $route_count_4 + $route_count_5 + $route_count_6]
if {$max_route_count <  $total_route_count} {set max_route_count $total_route_count}
	set total_free_count [expr $total_free_count + $total_route_count]

	puts $fl "Metal 1 - $route_count_1, Metal 2 - $route_count_2, Metal 3 - $route_count_3, Metal 4 - $route_count_4, Metal 5 - $route_count_5, Metal 6 - $route_count_6"
	puts $fl "Sites:"

	puts $fl "$site_coords"
	puts $fl "[llength $site_coords] Sites\n\n"
	set final_site_count [expr $final_site_count + [llength $site_coords]]
	if {$max_site_count < [llength $site_coords]} {set max_site_count [llength $site_coords]}
}
close $fl
