package ru.vniins.ais.realty.subsystem.hab.web;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.hateoas.*;
import org.springframework.hateoas.core.Relation;
import org.springframework.http.HttpEntity;
import org.springframework.web.bind.annotation.*;
import ru.vniins.ais.realty.shared.EncodableEnum;
import ru.vniins.ais.realty.shared.defs.*;
import ru.vniins.ais.realty.subsystem.adm.domain.*;
import ru.vniins.ais.realty.subsystem.reg.domain.*;
import javax.persistence.*;
import javax.persistence.criteria.*;
import java.util.*;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
import static ru.vniins.ais.realty.engine.web.EngineController.REPORTS_PATH;
@Slf4j
@RestController
@RequestMapping(REPORTS_PATH + "/hab")
public class HabitationReportsController {
private static final String TOTAL_AREA_REL = "totalAreaByMilitaryUnit";
@PersistenceContext
private EntityManager em;
@RequestMapping
public ResourceSupport reports() {
ResourceSupport resource = new ResourceSupport();
resource.add(asList(
linkTo(methodOn(HabitationReportsController.class).totalArea()).withRel(TOTAL_AREA_REL)
));
return resource;
}
@RequestMapping("/totalAreaByMilitaryUnit")
public HttpEntity<Resources<Object>> totalArea() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> query = cb.createTupleQuery();
Root<RealEstate> est = query.from(RealEstate.class);
est.join(RealEstate_.linkedMilitaryUnit);
Path<String> munitNameField = est.get(RealEstate_.linkedMilitaryUnit).get(MilitaryUnit_.name);
Path<Integer> typeField = est.get(RealEstate_.habitationType);
Path<Integer> soaField = est.get(RealEstate_.sourceOfAcquisition);
Selection<Double> totalArea = cb.sum(est.get(RealEstate_.totalArea)).alias("totalArea");
final Selection<Long> count = cb.count(est.get(RealEstate_.id)).alias("count");
query
.multiselect(
munitNameField,
typeField,
soaField,
totalArea,
count
)
.groupBy(munitNameField, typeField, soaField)
.where(cb.equal(est.get(RealEstate_.type), RealtyType.FLAT.getCode()));
TypedQuery<Tuple> q = em.createQuery(query);
List<Object> result = new ArrayList<>();
/* Map<String, Object> total = new HashMap<String, Object>() {{
put("totalArea", 0.0);
put("count", 0L);
}};
Map<HabitationType, Map<String, Object>> byHabType = new HashMap<>();
for (HabitationType type : HabitationType.values()) {
byHabType.put(type, new HashMap<String, Object>() {{
put("totalArea", 0.0);
put("count", 0L);
put("habitationType", type);
}});
}*/
for (Tuple tuple : q.getResultList()) {
/* Map<String, Object> map = new HashMap<>();
map.put("militaryUnitNumber", tuple.get(munitNameField));
map.put("habitationType", EncodableEnum.of(HabitationType.class, tuple.get(typeField)));
map.put("sourceOfAcquisition", EncodableEnum.of(SourceOfAcquisition.class, tuple.get(soaField)));
map.put("totalArea", tuple.get(totalArea));
map.put("count", tuple.get(count));*/
RealEstateStats stats = new RealEstateStats();
stats.setMilitaryUnit(tuple.get(munitNameField));
stats.setHabitationType(EncodableEnum.of(HabitationType.class, tuple.get(typeField)));
stats.setSourceOfAcquisition(EncodableEnum.of(SourceOfAcquisition.class, tuple.get(soaField)));
stats.setTotalArea(tuple.get(totalArea));
stats.setNumberOfFlats(tuple.get(count));
/* total.compute("totalArea", (s, i) -> (double) i + tuple.get(totalArea));
total.compute("count", (s, i) -> (long) i + tuple.get(count));
byHabType.compute(EncodableEnum.of(HabitationType.class, tuple.get(typeField)),
(type, m) -> {
m.compute("totalArea", (s, i) -> (double) i + tuple.get(totalArea));
m.compute("count", (s, i) -> (long) i + tuple.get(count));
return m;
});*/
result.add(stats);
}
/* result.add(total);
result.addAll(byHabType.values().stream().filter(m -> !m.isEmpty()).collect(toList()));*/
return new HttpEntity<>(new Resources<Object>(result));
}
@Data
@Relation(collectionRelation = "realEstateStats")
@JsonInclude(JsonInclude.Include.NON_NULL)
private static class RealEstateStats {
private String militaryUnit;
private Long numberOfFlats;
private Double totalArea;
private HabitationType habitationType;
private SourceOfAcquisition sourceOfAcquisition;
}
}