#include <stdio.h>
#include <string.h>
// this is modified Mozilla's library file, I need it just to have same constants
#include "nsSBCharSetProber.h"
 
void find_frequency(char [], int []);
unsigned char Buff[1024];

// modified KOI8 frequency table, allowed apostrophe "'"
unsigned char KOI8R_CharToOrderMap[] =
{
255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255,  //00
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  //10
253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,  //20
252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253,  //30
253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154,  //40
155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253,  //50
253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69,  //60
 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253,  //70
191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,  //80
207,208,209,210,211,212,213,214,215,216,253,218,219,220,221,222,  //90
223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237,  //a0
238,239,240,241,242,243,244,245,246,247,248,249,250,251,250,250,  //b0
 27,  3, 21, 28, 13,  2, 39, 19, 26,  4, 23, 11,  8, 12,  5,  1,  //c0
 15, 16,  9,  7,  6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54,  //d0
 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34,  //e0
 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70,  //f0
};

// just a stub, would be filled later
unsigned char KOI8U_CharToOrderMap[] =
{
255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255,  //00
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  //10
253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,  //20
252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253,  //30
253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154,  //40
155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253,  //50
253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69,  //60
 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253,  //70
191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,  //80
207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,  //90
223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237,  //a0
238,239,240,241,242,243,244,245,246,247,248,249,250,251,250,250,  //b0
 27,  3, 21, 28, 13,  2, 39, 19, 26,  4, 23, 11,  8, 12,  5,  1,  //c0
 15, 16,  9,  7,  6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54,  //d0
 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34,  //e0
 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70,  //f0
};

// original Russian model, just for tests
char RussianLangModel[] = 
{
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,2,3,3,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,2,2,2,2,2,0,0,2,
3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1,
0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1,
0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0,
0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0,
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1,
1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1,
1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0,
2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1,
1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0,
3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1,
1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0,
2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2,
1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1,
1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1,
1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,
2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1,
1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,
3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2,
1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,
2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1,
1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0,
2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0,
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1,
1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0,
1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1,
1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0,
3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1,
2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1,
3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1,
1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1,
1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1,
0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,
2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1,
1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0,
1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,
0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1,
1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2,
2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1,
1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0,
1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0,
2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,
1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,
0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,
2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1,
1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1,
1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,
0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1,
0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,
1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,
0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,
0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,
1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,
0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0,
0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
};

unsigned int cUkrainianLangModel[SAMPLE_SIZE*SAMPLE_SIZE] = {0};
char UkrainianLangModel[SAMPLE_SIZE*SAMPLE_SIZE] = {0};

int main(int argc,char *argv[])
{
  FILE *fp;
  int n;
  int j, c, count[256] = {0};
  unsigned char a;
  int last_max_count=0, next_max_count=0;

  if(argc < 2)
    return 1;

  if((fp=fopen(argv[1],"rb")) == NULL)
    return 2;

  // Calculate characters
  while((n = fread(Buff,1,sizeof(Buff),fp))>0) {
    for(c=0; c<n; c++) {
      a = Buff[c];
      if(KOI8R_CharToOrderMap[a]>251 && a!=0x27 /* ' */) {
        continue;
      }
      count[a]++;
      if(a>0x80 || a==0x27) {
        count[a]+=20;
      }
      //printf("count[%x]=%u\n", a, count[a]);
      if(count[a]>last_max_count) {
        last_max_count=count[a];
      }
    }
  }
  
  fclose(fp);

  // Sort characters by frequency, code (in case we have several chars with same frequency)
  // We use a bit modified KOI8R matrix as template for ignored characters
  // Also, we include apostropy in list of valid letters since it is often used in Ukrainian
  n = 0;
  for (c = 0 ; c < 256 ; c++) {
    for(j=0; j<256; j++) {
      //printf("count[%x]=%u vs %u\n", j, count[j], last_max_count);
      if(count[j]==last_max_count) {
        if(KOI8R_CharToOrderMap[j]<=251 || j==0x27 /* ' */) {
          KOI8U_CharToOrderMap[j]=(last_max_count?n:253);
        } else {
          KOI8U_CharToOrderMap[j]=KOI8R_CharToOrderMap[j];
        }
        n++;
      }
      if(count[j]>next_max_count && count[j]<last_max_count) {
        next_max_count = count[j];
      }
    }
    if(!last_max_count) {
      break;
    }
    last_max_count = next_max_count;
    next_max_count = 0;
  }
  
  // print final CharToOrderMap
  printf("unsigned char KOI8U_CharToOrderMap[] =\n{\n");
  for (c = 0 ; c < 256 ; c++) {
    a = KOI8U_CharToOrderMap[c];
    if(a<10) {
      printf(" ");
    }
    if(a<100) {
      printf(" ");
    }
    printf("%u,", a);
    if(c % 16 == 15) {
      printf(" //%2.2x\n", c & 0xf0);
    }
  }
  printf("};\n");

  unsigned char order;
  unsigned char mLastOrder;

  unsigned int mTotalSeqs;
  unsigned int mSeqCounters[NUMBER_OF_SEQ_CAT];

  unsigned int mTotalChar;
  //characters that fall in our sampling range
  unsigned int mFreqChar;

  mLastOrder = 255;
  for (unsigned int i = 0; i < NUMBER_OF_SEQ_CAT; i++)
    mSeqCounters[i] = 0;
  mTotalSeqs = 0;
  mTotalChar = 0;
  mFreqChar = 0;

  if((fp=fopen(argv[1],"rb")) == NULL)
    return 2;

  // calculate character pairs
  while((n = fread(Buff,1,sizeof(Buff),fp))>0) {
    for(c=0; c<n; c++) {
      a = Buff[c];
      order = KOI8U_CharToOrderMap[a];

      if (order < SYMBOL_CAT_ORDER)
        mTotalChar++;
      if (order < SAMPLE_SIZE)
      {
        mFreqChar++;

        if (mLastOrder < SAMPLE_SIZE)
        {
          mTotalSeqs++;
          cUkrainianLangModel[mLastOrder*SAMPLE_SIZE+order]++;
        }
      }
      mLastOrder = order;
    }
  }

  // Print table with counters, just for debug
  printf("\n/*\n");
  for (c = 0 ; c < SAMPLE_SIZE*SAMPLE_SIZE ; c++) {
    n = cUkrainianLangModel[c];
    if(a<10) {
      printf(" ");
    }
    if(a<100) {
      printf(" ");
    }
    printf("%u,", n);
    if(c % 32 == 31) {
      printf(" \n");
    }
  }
  printf("*/\n");

  int limit23 = mTotalSeqs/(SAMPLE_SIZE*SAMPLE_SIZE);
  int limit23_step = limit23/2;
  int count3;
  int limit12 = limit23/2;
  int limit12_step = limit12/2;
  int count2;

  // Find thresholda for ~515 (1/8 of all possible pairs) of most significant pais
  // and ~1024 (1/4) of less significant
  // Treat 0 as definitly NEVER USED and everything between 1 and 2nd threshold as OTHER
  // Sorry, a bit 'heuristic' algorithm, just quick
  for(j=0;j<SAMPLE_SIZE;j++) {
    count3 = 0;
    count2 = 0;
    for (c = 0 ; c < SAMPLE_SIZE*SAMPLE_SIZE ; c++) {
      if(cUkrainianLangModel[c] >= limit23) {
        count3++;
      } else
      if(cUkrainianLangModel[c] >= limit12) {
        count2++;
      }
    }
    //printf("// limit23=%u (%u) step %u\n", limit23, count3, limit23_step);
    //printf("// limit12=%u (%u) step %u\n", limit12, count2, limit12_step);
    if(count3>SAMPLE_SIZE*SAMPLE_SIZE/8) {
      limit23 += limit23_step;
      limit23_step /= 2;
    } else
    if(count3<SAMPLE_SIZE*SAMPLE_SIZE/8) {
      if(limit23<=limit23_step) {
        limit23_step = limit23/2;
      }
      limit23 -= limit23_step;
      limit23_step /= 2;
    }
    if(count2>SAMPLE_SIZE*SAMPLE_SIZE/4) {
      limit12 += limit12_step;
      limit12_step /= 2;
    } else
    if(count2<SAMPLE_SIZE*SAMPLE_SIZE/4) {
      if(limit12<=limit12_step) {
        limit12_step = limit12/2;
      }
      limit12 -= limit12_step;
      limit12_step = (limit12_step*2)/3;
    }
    if(!limit23_step && !limit23_step) {
      //break;
    }
    if(!limit23_step) {
      limit23_step = 4;
    }
    if(!limit12_step) {
      limit12_step = 4;
    }
  }

  printf("// limit23=%u (%u)\n", limit23, count3);
  printf("// limit12=%u (%u)\n", limit12, count2);

  // Print final LanguageModel
  printf("char UkrainianLangModel[] =\n{\n");
  for (c = 0 ; c < SAMPLE_SIZE*SAMPLE_SIZE ; c++) {
    n = cUkrainianLangModel[c];

    if(n>limit23) {
      a = 3;
    } else
    if(n>limit12) {
      a = 2;
    } else
    if(n) {
      a = 1;
    } else {
      a = 0;
    }
    UkrainianLangModel[c] = a;
    printf("%u,", a);
    if(c % 32 == 31) {
      printf(" \n");
    }
  }
  printf("};\n");

  /* AND NOW TEST OUR MODEL */

  mLastOrder = 255;
  for (unsigned int i = 0; i < NUMBER_OF_SEQ_CAT; i++)
    mSeqCounters[i] = 0;
  mTotalSeqs = 0;
  mTotalChar = 0;
  mFreqChar = 0;

  // try open test file specified in 2nd arg
  // or use the same if none specified
  if(argc > 2) {
    if((fp=fopen(argv[2],"rb")) == NULL)
      return 2;
  } else {
    if((fp=fopen(argv[1],"rb")) == NULL)
      return 2;
  }

  // calculate probability according to our model
  // here I've commented for debug purposes check against original Russian model
  // Uncoment and see the difference
  while((n = fread(Buff,1,sizeof(Buff),fp))>0) {
    for(c=0; c<n; c++) {
      a = Buff[c];
      order = KOI8U_CharToOrderMap[a];
      //order = KOI8R_CharToOrderMap[a];

      if (order < SYMBOL_CAT_ORDER)
        mTotalChar++;
      if (order < SAMPLE_SIZE)
      {
        mFreqChar++;

        if (mLastOrder < SAMPLE_SIZE)
        {
          mTotalSeqs++;
          ++(mSeqCounters[(unsigned)UkrainianLangModel[mLastOrder*SAMPLE_SIZE+order]]);
          //++(mSeqCounters[(unsigned)RussianLangModel[mLastOrder*SAMPLE_SIZE+order]]);
        }
      }
      mLastOrder = order;
    }
  }

  float r;

  if (mTotalSeqs > 0) {
    r = ((float)1.0) * mSeqCounters[POSITIVE_CAT] / mTotalSeqs / 1;
    printf("// %u / %u\n", mSeqCounters[POSITIVE_CAT] , mTotalSeqs);
    r = r*mFreqChar/mTotalChar;
    if (r >= (float)1.00)
      r = (float)0.99;
  } else {
    r = (float)0.01;
  }
  printf("// r=%f\n", r);

  return 0;
}
 
