import java.io.*;
import java.util.*;

public class TableTestGen {

	final static int MAX_N = 1_000;
	final static int MAX_K = 1_000;
	final static int MAX_A = 1_000;
	final static Random rng = new Random("table".hashCode());

	public static void main(String[] args) throws Exception {
		new TableTestGen().generate();
	}

	PrintWriter out;
	int countTests = 0;

	void generate() {
		generateSamples();

		generateSmall();
		generateMedium();
		generateLarge();
	}

	int[] randomPermutation(int length) {
		int[] a = new int[length];
		for (int i = 0; i < length; i++) {
			a[i] = i;
			int pos = rng.nextInt(i + 1);

			int tmp = a[i];
			a[i] = a[pos];
			a[pos] = tmp;
		}
		return a;
	}

	private void generateSmall() {
		printTest(new int[][] { { 1 } });
		printTest(new int[][] { { MAX_A, MAX_A - 1 }, { MAX_A, MAX_A } });
		printTest(new int[][] { { 3, 1, 2 } });
		printTest(new int[][] { { 1 }, { 1 }, { 1 } });
		printTest(new int[][] { { 1 }, { 2 }, { 1 } });

		for (int i = 5; i < 10; i++) {
			int n = i, m = i;
			printRandomTest(n, m, 1, n);
		}

		for (int i = 0; i < 5; i++) {
			final int max = 20;
			int n = rng.nextInt(max) + 1;
			int m = rng.nextInt(max) + 1;
			printRandomTest(n, m, 1, 5);
		}
	}

	void printRandomTest(final int n, final int m, final int minA,
			final int maxA) {
		int[][] a = new int[n][m];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				a[i][j] = rng.nextInt(maxA - minA + 1) + minA;
			}
		}

		final int[] p = randomPermutation(m);
		Arrays.sort(a, new Comparator<int[]>() {
			@Override
			public int compare(int[] o1, int[] o2) {
				for (int i = 0; i < m; i++) {
					int val1 = o1[p[i]], val2 = o2[p[i]];
					if (val1 != val2) {
						return val1 - val2;
					}
				}
				return 0;
			}
		});

		printTest(a);
	}

	private void generateMedium() {
		for (int i = 0; i < 5; i++) {
			final int max = 100;
			int n = rng.nextInt(max) + 101;
			int m = rng.nextInt(max) + 101;
			printRandomTest(n, m, 1, (i + 1) * 10);
		}
	}

	private void generateLarge() {
		for (int i = 0; i < 5; i++) {
			int n = 1000;
			int m = 1000;
			printRandomTest(n, m, 1, MAX_A);
		}

		{
			int n = 1000, m = 1000;
			int[][] a = new int[n][m];
			for (int i = 0; i < n; i++) {
				Arrays.fill(a[i], 1);
				a[i][m - 1 - i] = 2;
			}
			printTest(a);

			for (int i = 0; i < n; i++) {
				Arrays.fill(a[i], 1);
				a[i][i] = 2;
			}
			printTest(a);
		}

		{
			int n = 1000, m = 1;
			int[][] a = new int[n][m];
			a[0][0] = 1;
			for (int i = 1; i < n; i++) {
				a[i][0] = a[i - 1][0] + rng.nextInt(2) + rng.nextInt(2);
			}
			printTest(a);

			for (int i = 0; i < n; i++) {
				a[i][0] = MAX_A;
			}
			printTest(a);
		}

		{
			int n = 1, m = 1000;
			int[][] a = new int[n][m];
			a[0][0] = 1;
			for (int i = 1; i < m; i++) {
				a[0][i] = a[0][i - 1] + rng.nextInt(2) + rng.nextInt(2);
			}
			printTest(a);

			for (int i = 0; i < m; i++) {
				a[0][i] = MAX_A;
			}
			printTest(a);
		}

		{
			int n = 1000, m = 1000;
			int[][] a = new int[n][m];
			for (int i = 0; i < n; i++) {
				Arrays.fill(a[i], 1);
			}
			printTest(a);

			a[n - 2][m - 2] = a[n - 1][m - 2] = a[n - 2][m - 1] = 2;
			printTest(a);
		}
		
		{
			int n = 1000, m = 1000;
			int[][] a = new int[n][m];
			for (int i = 0; i < n; i++) {
				Arrays.fill(a[i], 1);
			}
			printTest(a);

			a[n - 2][m - 2] = a[n - 1][m - 1] = 2;
			printTest(a);
		}
		
		{
			int n = 1000, m = 1000;
			int[][] a = new int[n][m];
			for (int i = 0; i < n; i++) {
				Arrays.fill(a[i], 1);
			}
			printTest(a);

			a[n - 1][m - 2] = a[n - 1][m - 2] = 2;
			printTest(a);
		}
		
		{
			int n = 1000, m = 1000;
			int[][] a = new int[n][m];
			for (int i = 0; i < n; i++) {
				Arrays.fill(a[i], 1);
			}
			
			for (int i = n - 1; i >= 0; i--) {
				a[i][i] = (n - i + 1);
				for (int j = 0; j < i; j++) {
					a[j][i] = a[i][i] - 1;
				}
			}
			printTest(a);
		}
	}

	private void generateSamples() {
		printTest(new int[][] { { 2, 2, 1 }, { 2, 3, 1 }, { 3, 1, 2 } });
		printTest(new int[][] { { 2, 1 }, { 1, 1 } });
	}

	void printTest(int[][] a) {
		try {
			countTests++;
			String fileName = "../tests/";
			fileName += String.format("%02d", countTests);
			out = new PrintWriter(fileName);

			int n = a.length, k = a[0].length;
			out.println(n + " " + k);
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < k; j++) {
					out.print(a[i][j]);
					if (j + 1 == k) {
						out.println();
					} else {
						out.print(" ");
					}
				}
			}

			System.out.println("Done printing test #" + countTests);
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
}
