/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* Copyright (c) 2013, MPL CodeInside http://codeinside.ru
*/
package ru.codeinside.adm.parser;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.lang.StringUtils;
import ru.codeinside.adm.AdminServiceProvider;
import ru.codeinside.adm.database.Role;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.apache.commons.lang.StringUtils.defaultIfEmpty;
import static org.apache.commons.lang.StringUtils.trimToNull;
/**
* Разбор файла фикстур с данными о сотрудниках и организициях
*/
public class EmployeeFixtureParser {
private final Splitter groupSplitter;
private final LinkedList<Row> stack;
private final Pattern snilsPattern = Pattern.compile("\\d{11}");
public EmployeeFixtureParser() {
groupSplitter = Splitter.on(',').trimResults().omitEmptyStrings();
stack = new LinkedList<Row>();
}
public void loadFixtures(InputStream is, EmployeeFixtureParser.PersistenceCallback callback) throws IOException {
final Splitter propertySplitter = Splitter.on(';');
final BufferedReader reader = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String line;
int lineNumber = 0;
while ((line = reader.readLine()) != null) {
lineNumber++;
int level = startIndex(line);
if (line.startsWith("#") || level < 0) {
continue;
}
final ArrayList<String> props = Lists.newArrayList(propertySplitter.split(line.substring(level)));
final String name = StringUtils.trimToNull(props.get(0));
if (name == null) {
if (props.size() == 1) {
continue;
}
throw new IllegalStateException("Пропущено имя( строка:" + lineNumber + ")");
} else if (name.length() >= 255) {
throw new IllegalStateException("Длина имени не должна превышать 255 символов (строка: "+lineNumber+")");
}
final boolean isOrg = props.size() <= 2;
Row parent = getParentRow(level);
final Set<String> groups = parseGroups(props, getGroupPropertyIndex(isOrg));
if (isOrg) {
long orgId = callback.onOrganizationComplete(name, groups, parent != null ? parent.id : null);
stack.addLast(new Row(level, orgId));
}
if (!isOrg && parent != null) {
String pwd = defaultIfEmpty(trimToNull(props.get(2)), null);
Set<Role> roles = parseRoles(groupSplitter, lineNumber, props.get(3));
String snils = "";
if (props.size() == 6) {
String snilsValue = defaultIfEmpty(trimToNull(props.get(5)), null);
Matcher snilsMatcher = snilsPattern.matcher(snilsValue);
if (snilsMatcher.matches() && AdminServiceProvider.get().isUniqueSnils(name, snilsValue)) {
snils = snilsValue.replaceAll("\\D+", "");
}
}
callback.onUserComplete(StringUtils.trim(props.get(1)), pwd, name, snils, parent.id, roles, groups);
}
if (!isOrg && parent == null) {
throw new IllegalStateException("Пользователь без организации(строка:" + lineNumber + ").");
}
}
}
private Row getParentRow(int level) {
Row parent = stack.isEmpty() ? null : stack.getLast();
while (!stack.isEmpty()) {
if (parent != null && (parent.level < level)) {
break;
}
stack.removeLast();
parent = stack.isEmpty() ? null : stack.getLast();
}
return parent;
}
private int getGroupPropertyIndex(boolean org) {
return org ? 1 : 4;
}
private Set<String> parseGroups(ArrayList<String> props, int propertyGroupIndex) {
final Set<String> groups;
if (props.size() > propertyGroupIndex) {
groups = Sets.newTreeSet(groupSplitter.split(props.get(propertyGroupIndex)));
} else {
groups = Collections.emptySet();
}
return groups;
}
private Set<Role> parseRoles(Splitter groupSplitter, int lineNumber, String rolesString) {
Set<String> roleNames = Sets.newTreeSet(groupSplitter.split(rolesString));
Set<Role> roles = EnumSet.noneOf(Role.class);
for (String roleName : roleNames) {
try {
roles.add(Role.valueOf(roleName));
} catch (Exception e) {
throw new IllegalStateException("Неизвестная роль ( строка:" + lineNumber + "):" + roleName);
}
}
return roles;
}
private int startIndex(String line) {
int N = line.length();
for (int i = 0; i < N; i++) {
char c = line.charAt(i);
if (c != ' ') {
return i;
}
}
return -1;
}
public interface PersistenceCallback {
Long onOrganizationComplete(String orgName, Set<String> groups, Long ownerId);
void onUserComplete(String login, String pwd, String name, String snils, long orgId, Set<Role> roles, Set<String> groups);
}
final static class Row {
final int level;
final long id;
Row(int level, long id) {
this.level = level;
this.id = id;
}
}
}