/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package cli_fmw.directory.editors.kladr;
import cli_fmw.delegate.directory.complex.DirectoryKladr;
import cli_fmw.delegate.directory.complex.DirectoryKladrType;
import cli_fmw.delegate.directory.complex.DirectoryKladrTypeItem;
import cli_fmw.delegate.directory.complex.DirectoryLocator;
import cli_fmw.main.ClipsException;
import cli_fmw.utils.SelectorEditableExceptional;
import framework.beans.address.KladrCode;
import framework.beans.address.KladrItem;
import framework.beans.address.entities.AddressObjectTypeDetails;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.xBaseJ.micro.DBF;
import org.xBaseJ.micro.fields.CharField;
import org.xBaseJ.micro.xBaseJException;
/**
* Разбирает адрес в формате КЛАДРАа и заполняет структуру для
* загрузки его в базу
* @author petr
*/
public class DBaseParser {
public static final String ALTNAMES = "ALTNAMES.DBF";
public static final String DOMA = "DOMA.DBF";
public static final String FLAT = "FLAT.DBF";
public static final String KLADR = "KLADR.DBF";
public static final String SOCRBASE = "SOCRBASE.DBF";
public static final String STREET = "STREET.DBF";
/**6*/
private static final int code_section_count = KladrCode.MAX_LENGHT;//начинаем с 1, вопросы к авторам кладра
private static final int f_type_level = 0;
private static final int f_type_abbriv = 1;
private static final int f_type_title = 2;
private static final int f_type_code = 3;
private static final int f_title = 0;
private static final int f_abbriv = 1;
private static final int f_code = 2;
private static final int f_index = 3;
private static final int f_codeIfns = 4;
private static final int f_localCodeIfns = 5;
private static final int f_okato = 6;
private static final int f_status = 7;
//for fucking crazy humanoids who born file "doma.dbf"
private static final int f_doma_title = 0;
private static final int f_doma_corp = 1;
private static final int f_doma_abbriv = 2;
private static final int f_doma_code = 3;
private static final int f_doma_index = 4;
private static final int f_doma_codeIfns = 5;
private static final int f_doma_localCodeIfns = 6;
private static final int f_doma_okato = 7;
//for altnames
private static final int f_old_code = 0;
private static final int f_new_code = 1;
private static final int f_level = 2;
private File db;
private File altnames = null;
private File doma = null;
private File flat = null;
private File kladr = null;
private File socrbase = null;
private File street = null;
private ArrayList<AddressObjectTypeDetails> types;
private ArrayList<KladrItem> addressRoots;
/** Map<ladr code, directory item> */
private Map<KladrCode, KladrItem> items;
/** Map<needing paren code, List<directory item>>*/
private Map<KladrCode, Set<KladrItem>> notAddedYet;
/** Map<Abbrivation+Level, directory type item>*/
private Map<String, DirectoryKladrTypeItem> kladrTypes;
/** Map<old kladr code, new kladr code>*/
private Map<KladrCode, KladrCode> altNames;
private DirectoryKladrType directoryKladrType;
private DirectoryKladr directoryKladr;
/**
*
* @param db
* @throws java.io.IOException
*/
public DBaseParser(File db) throws ClipsException {
this.db = db;
if (db.isDirectory()) {
File[] filesInDir = db.listFiles();
for (File f : filesInDir) {
System.out.println("file: " + f.getName());
if (f.isFile()) {
if (f.getName().equalsIgnoreCase(DBaseParser.ALTNAMES)) {
altnames = f;
} else if (f.getName().equalsIgnoreCase(DBaseParser.DOMA)) {
doma = f;
} else if (f.getName().equalsIgnoreCase(DBaseParser.FLAT)) {
flat = f;
} else if (f.getName().equalsIgnoreCase(DBaseParser.KLADR)) {
kladr = f;
} else if (f.getName().equalsIgnoreCase(DBaseParser.SOCRBASE)) {
socrbase = f;
} else if (f.getName().equalsIgnoreCase(DBaseParser.STREET)) {
street = f;
}
}
}
}
if (altnames == null) {
throw new ClipsException("Не найден файл" + DBaseParser.ALTNAMES);
}
if (doma == null) {
throw new ClipsException("Не найден файл" + DBaseParser.DOMA);
}
if (flat == null) {
throw new ClipsException("Не найден файл" + DBaseParser.FLAT);
}
if (kladr == null) {
throw new ClipsException("Не найден файл" + DBaseParser.KLADR);
}
if (socrbase == null) {
throw new ClipsException("Не найден файл" + DBaseParser.SOCRBASE);
}
if (street == null) {
throw new ClipsException("Не найден файл" + DBaseParser.STREET);
}
init();
remapTypes();
System.out.println("DBASEPARSER: dBase parser was created");
// DirectoryMKB10 mKB10 = DirectoryLocator.getDirectory(DirectoryMKB10.class, false);
// DirectoryDialogDefaultCombo dddc = new DirectoryDialogDefaultCombo(MainWindow.mainWindow, mKB10);
// dddc.setVisible(true);
// throw new ClipsException();
}
private void init() {
//initializing
types = new ArrayList<AddressObjectTypeDetails>();
items = new TreeMap<KladrCode, KladrItem>();
notAddedYet = new TreeMap<KladrCode, Set<KladrItem>>();
addressRoots = new ArrayList<KladrItem>();
}
/**
* запускает разбор файлов КЛАДРа
* @throws cli_fmw.main.ClipsException
*/
public void run() throws ClipsException {
System.out.println("DBASEPARSER: parsing was started");
directoryKladr = (DirectoryKladr) DirectoryLocator.getDirectory(DirectoryKladr.class, false);
directoryKladrType = (DirectoryKladrType) DirectoryLocator.getDirectory(DirectoryKladrType.class, false);
parseSocrBase(socrbase);
directoryKladrType.syncDirectory(types);
remapTypes();
parseAltNames(altnames);
parseKladr(kladr);
parseKladr(street);
parseDoma(doma);
// while(MessageBox.showConfirmYesNo(MessageBox.C_OVERWRITE_FILE, "Загрузить КЛАДР") == MessageBox.ANSWER_YES){
// try{
directoryKladr.syncDirectory(addressRoots, altNames);
// }catch(Exception ex){
// ex.printStackTrace();
// }
// }
System.out.println("DBASEPARSER: parsing was canceled");
}
private void parseAltNames(File altnames) throws ClipsException {
DBF dbf = createDBF(altnames);
CharField[] fields = getFields(dbf);
int recordCount = dbf.getRecordCount();
String s = null;
int c = 0;
for (c = 1; c <= recordCount; c++) {
try {
dbf.read();
KladrCode oldCode = null;
KladrCode newCode = null;
for (int i = 0; i < fields.length; i++) {
s = new String(fields[i].get().trim());
switch (i) {
case f_old_code:
oldCode = new KladrCode(parseCode(s));
break;
case f_new_code:
newCode = new KladrCode(parseCode(s));
break;
case f_level: {
//do nothing
}
}
}
altNames.put(newCode, oldCode);
} catch (xBaseJException ex) {
throw new ClipsException("Ошибка при чтении данных из файла " + dbf.getName(), ex);
} catch (IOException ex) {
throw new ClipsException("Не найден файл " + dbf.getName(), ex);
}
}
}
/**
* разбирает таблицу сокращений
* @param dbf
*/
private void parseSocrBase(File f) throws ClipsException {
DBF dbf = createDBF(f);
CharField[] fields = getFields(dbf);
int recordCount = dbf.getRecordCount();
String s = null;
int c = 0;
for (c = 1; c <= recordCount; c++) {
try {
dbf.read();
AddressObjectTypeDetails type = new AddressObjectTypeDetails();
for (int i = 0; i < fields.length; i++) {
s = new String(fields[i].get().trim());
switch (i) {
case f_type_level:
type.level = Integer.parseInt(s);
break;
case f_type_abbriv:
type.abbrivation = s;
break;
case f_type_title:
type.title = s;
break;
case f_type_code:
type.code = Integer.parseInt(s);
break;
}
}
types.add(type);
} catch (xBaseJException ex) {
throw new ClipsException("Ошибка при чтении данных из файла " + dbf.getName(), ex);
} catch (IOException ex) {
throw new ClipsException("Не найден файл " + dbf.getName(), ex);
}
}
// for (AddressObjectTypeDetails type : types) {
// System.out.println(type.title + " " + type.abbrivation + " " + type.level + " " + type.code);
// }
}
/**
* for fucking crazy humanoids who born file "doma.dbf"
* @param dbf
*/
private void parseDoma(File f) throws ClipsException {
types = new ArrayList<AddressObjectTypeDetails>();
DBF dbf = createDBF(f);
CharField[] fields = getFields(dbf);
int recordCount = dbf.getRecordCount();
String s = null;
String code = null;
String abbr = null;
int c = 0;
for (c = 1; c < recordCount; c++) {
try {
dbf.read();
KladrItem item = new KladrItem();
for (int i = 0; i < fields.length; i++) {
s = new String(fields[i].get().trim());
// System.out.print(s + " ");
switch (i) {
case f_doma_title:
item.title = s;
break;
case f_doma_corp:
item.title += s;
case f_doma_abbriv:
abbr = s;
break;
case f_doma_code:
code = s;
break;
case f_doma_index:
item.postIndex = s.isEmpty() ? 0 : Integer.parseInt(s);
break;
case f_doma_codeIfns:
item.ifnsCode = s.isEmpty() ? 0 : Integer.parseInt(s);
break;
case f_doma_localCodeIfns:
item.ifnsLocalCode = s.isEmpty() ? 0 : Integer.parseInt(s);
break;
case f_doma_okato:
item.okato = s.isEmpty() ? 0 : Long.parseLong(s);
break;
}
}
addKladrObject(code, abbr, item);
// System.out.println();
if (c % 1000 == 0) {
System.out.println("process " + c + " records");
}
} catch (xBaseJException ex) {
throw new ClipsException("Ошибка при чтении данных из файла " + dbf.getName(), ex);
} catch (IOException ex) {
throw new ClipsException("Не найден файл " + dbf.getName(), ex);
}
}
}
/**
* разбирает файл кладра
* @param f файл должен быть таблицей в дБейс формате
* @throws org.xBaseJ.micro.xBaseJException
* @throws java.io.IOException
*/
private void parseKladr(File f) throws ClipsException {
DBF dbf = createDBF(f);
CharField[] fields = getFields(dbf);
int recordCount = dbf.getRecordCount();
String s = null;
String code = null;
String abbr = null;
int c = 0;
for (c = 1; c <= recordCount; c++) {
try {
dbf.read();
KladrItem item = new KladrItem();
for (int i = 0; i < fields.length; i++) {
s = new String(fields[i].get().trim());
// System.out.print(s + " ");
switch (i) {
case f_title:
item.title = s;
break;
case f_abbriv:
abbr = s;
break;
case f_code:
code = s;
break;
case f_index:
item.postIndex = s.isEmpty() ? 0 : Integer.parseInt(s);
break;
case f_codeIfns:
item.ifnsCode = s.isEmpty() ? 0 : Integer.parseInt(s);
break;
case f_localCodeIfns:
item.ifnsLocalCode = s.isEmpty() ? 0 : Integer.parseInt(s);
break;
case f_okato:
item.okato = s.isEmpty() ? 0 : Long.parseLong(s);
break;
case f_status:
//нах это поле
break;
}
}
addKladrObject(code, abbr, item);
// System.out.println();
if (c % 1000 == 0) {
System.out.println("process " + c + " records");
}
} catch (xBaseJException ex) {
throw new ClipsException("Ошибка при чтении данных из файла " + f.getName(), ex);
} catch (IOException ex) {
throw new ClipsException("Не найден файл " + f.getName(), ex);
}
}
}
/**
* создаёт дбф файл из данного
* @param f
* @return
* @throws cli_fmw.main.ClipsException
*/
private DBF createDBF(File f) throws ClipsException {
String filename = f.getName();
try {
DBF dbf = new DBF(f.getAbsolutePath(), "cp866");
System.out.println("DBASEPARSER: parse file '" + filename);
return dbf;
} catch (xBaseJException ex) {
throw new ClipsException("Ошибка при чтении данных из файла " + filename, ex);
} catch (IOException ex) {
throw new ClipsException("Не найден файл " + filename, ex);
}
}
/**
* Вытаскивает поля из таблицы
* @param dbf файл с таблицей
* @return
* @throws java.lang.ArrayIndexOutOfBoundsException
* @throws org.xBaseJ.micro.xBaseJException
*/
private CharField[] getFields(DBF dbf) throws ClipsException {
try {
int fieldCount = dbf.getFieldCount();
System.out.println("DBASEPARSER: item count: " + dbf.getRecordCount());
CharField[] fields = new CharField[fieldCount];
for (int i = 1; i <= fieldCount; i++) {
fields[i - 1] = (CharField) dbf.getField(i);
String fieldName = fields[i - 1].getName();
System.out.print(fieldName + " ");
}
System.out.println();
return fields;
} catch (ArrayIndexOutOfBoundsException ex) {
throw new ClipsException("Неверно определено количество полей в файле" + dbf.getName(), ex);
} catch (xBaseJException ex) {
throw new ClipsException("Ошибка при чтении данных из файла " + dbf.getName(), ex);
}
}
/**
* Разделяет код на составные части
* @param code
* @return массив с кодами конкретных уровней
* @throws cli_fmw.main.ClipsException
*/
private int[] parseCode(String code) throws ClipsException {
int[] cc;
int ln = code.length();
if (ln != 13 & ln != 17 & ln != 19) {
throw new ClipsException("Неверная длина кода КЛАДРа: " + ln);
}
try {//проверим код
cc = KladrCode.parseCode(code);
} catch (NumberFormatException ex) {
throw new ClipsException("Неправильный формат кода КЛАДРа", ex);
}
return cc;
}
/**
* определяет актуальность
* @param code
* @return истина если актуален
*/
private boolean isActual(String code) throws ClipsException {
try {
if (code.length() == 19) {
return true;//alwais actual
}
int pos = code.length() - 2;
return Integer.parseInt(code.substring(pos, pos + 2)) == 0;//актуальность
} catch (NumberFormatException ex) {
throw new ClipsException("Неправильный формат кода КЛАДРа", ex);
}
}
/**
* добавляет данные об итеме в структуру отправляемую на сервер
* @param code код КЛАДРа
* @param abbr сокращение названия типа
* @param item итем
* @throws cli_fmw.main.ClipsException
*/
private void addKladrObject(String code, String abbr, KladrItem item) throws ClipsException {
int itemLevel = 0;
int[] cc = parseCode(code);
if (isActual(code)) {//только для актуальных
if (cc[0] == 0) {
throw new ClipsException("Неверный код объекта: " + code);
}
//определяем уровень и код
item.kladrCode = new KladrCode(cc);
//оставляем только код родителя
for (int level = code_section_count - 1; level >= 0; level--) {
if (cc[level] > 0) {
itemLevel = level + 1;
cc[level] = 0;
break;
}
}
KladrCode parentCode = new KladrCode(cc);
//set type by abbrivation and level
DirectoryKladrTypeItem type = kladrTypes.get(abbr + itemLevel);
if (type == null) {
throw new ClipsException("Неизвестный тип адресуемого объекта (abbrivation: " + abbr + " level: " + itemLevel + "), обновите файл сокращений");
}
item.typeId = type.getID();
Set<KladrItem> childrenFromMap = notAddedYet.get(item.kladrCode); //add children from 'needParent' map
if (childrenFromMap != null) {
if (item.children == null) {
item.children = new ArrayList<KladrItem>();
}
item.children.addAll(childrenFromMap);
notAddedYet.remove(item.kladrCode); //and clear children list
}
items.put(item.kladrCode, item); //put into items
if (itemLevel == 1) { //root
addressRoots.add(item); //add item into roots
} else { //only for children
//find parent in map and add child into it
KladrItem parent = items.get(parentCode);//find parent
//if parent not created put item into 'needParent' map
if (parent == null) {
if (notAddedYet.get(parentCode) == null) {
notAddedYet.put(parentCode, new HashSet<KladrItem>());
}
notAddedYet.get(parentCode).add(item);
} else {//if parent was find
if (parent.children == null) {
parent.children = new ArrayList<KladrItem>();
}
parent.children.add(item);
}
}
}
return;
}
/**
* загружает типы КЛАДРа из справочника в мап
*/
private void remapTypes() throws ClipsException {
directoryKladrType = (DirectoryKladrType) DirectoryLocator.getDirectory(DirectoryKladrType.class, true);
kladrTypes = new HashMap<String, DirectoryKladrTypeItem>();
SelectorEditableExceptional<DirectoryKladrTypeItem> see = directoryKladrType.getItems();
for (int i = 0; i < see.size(); i++) {
DirectoryKladrTypeItem type = see.get(i);
kladrTypes.put(type.getAbbrivation() + type.getLevel(), type);
}
}
}