269 lines
8.8 KiB
JavaScript
269 lines
8.8 KiB
JavaScript
import query_string from 'query-string';
|
|
import moment from 'moment-timezone';
|
|
|
|
import EnergyDatum from './../models/energy_datum';
|
|
import ObjectUtil from './../../shared/utils/object';
|
|
import ArrayUtil from './../../shared/utils/array';
|
|
|
|
const ROUTES = [
|
|
{
|
|
path: /houses\/(\d+)\/?$/,
|
|
parameters: {1: 'house_id'}
|
|
}, {
|
|
path: /houses\/(\d+)\/(energy)\/(\d+)\/([^\/]+)\/([^\/]+)\/?$/,
|
|
parameters: { 1: 'house_id', 2: 'dataset', 3: 'year', 4: 'graph_attr', 5: 'view' }
|
|
}, {
|
|
path: /houses\/(\d+)\/(power)\/([^\/]+)\/(\d+)\/([^\/]+)\/?$/,
|
|
parameters: { 1: 'house_id', 2: 'dataset', 3: 'month', 4: 'year', 5: 'view' }
|
|
}, {
|
|
path: /(irradiance)\/([^\/]+)\/(\d+)\/([^\/]+)\/?$/,
|
|
parameters: { 1: 'dataset', 2: 'month', 3: 'year', 4: 'view' }
|
|
}
|
|
];
|
|
|
|
class StateManager {
|
|
|
|
constructor(createHistory, houses){
|
|
var state_manager = this;
|
|
|
|
state_manager.houses = houses;
|
|
|
|
state_manager.state = {
|
|
loading_data: false,
|
|
graph_attr: 'consumption',
|
|
view: 'graph',
|
|
dataset: 'power',
|
|
house_id: null,
|
|
house: null,
|
|
month: null,
|
|
year: null,
|
|
date_interval: null };
|
|
|
|
state_manager.history = createHistory();
|
|
state_manager.update_in_progress = false;
|
|
}
|
|
|
|
get month_i(){
|
|
return moment.monthsShort().indexOf(this.state.month);
|
|
}
|
|
|
|
get date_params(){
|
|
return ObjectUtil.filterKeys(this.state, ['year', 'month', 'date_interval']);
|
|
}
|
|
|
|
get month_range(){
|
|
var state_manager = this,
|
|
house = state_manager.state.house,
|
|
start_time = house.parseMoment(`${state_manager.state.year}-${state_manager.month_i + 1}-01`, 'YYYY-M-DD'),
|
|
end_time = start_time.clone().endOf('month').unix();
|
|
|
|
start_time = start_time.unix();
|
|
if (start_time < house.data.data_from) start_time = house.data.data_from;
|
|
if (end_time > house.data.data_until) end_time = house.data.data_until;
|
|
return [start_time, end_time];
|
|
}
|
|
|
|
get year_range(){
|
|
var state_manager = this,
|
|
house = state_manager.state.house,
|
|
start_time = house.parseMoment(`${state_manager.state.year}-01-01`, 'YYYY-MM-DD'),
|
|
end_time = start_time.clone().endOf('year').unix();
|
|
|
|
start_time = start_time.unix();
|
|
if (start_time < house.data.data_from) start_time = house.data.data_from;
|
|
if (end_time > house.data.data_until) end_time = house.data.data_until;
|
|
return [start_time, end_time];
|
|
}
|
|
|
|
matchesEnergyState(){
|
|
var state_manager = this,
|
|
house = state_manager.state.house,
|
|
energy_range = state_manager.state.graph_attr === 'irradiance' ? state_manager.state.date_interval : state_manager.year_range;
|
|
if (!house.state.energy_range) return false;
|
|
return energy_range[0] === house.state.energy_range[0] && energy_range[1] === house.state.energy_range[1];
|
|
}
|
|
|
|
matchesPowerState(){
|
|
var state_manager = this,
|
|
house = state_manager.state.house,
|
|
month_range = state_manager.month_range;
|
|
if (!house.state.power_range) return false;
|
|
return month_range[0] === house.state.power_range[0] && month_range[1] === house.state.power_range[1];
|
|
}
|
|
|
|
// This will update the house state acccording to passed update parameters.
|
|
updateHouseFromState(component){
|
|
var state_manager = this,
|
|
house = state_manager.state.house,
|
|
promise;
|
|
if (!house) {
|
|
promise = Promise.resolve();
|
|
} else if (state_manager.state.dataset === 'energy' && !state_manager.matchesEnergyState()){
|
|
promise = state_manager.setHouseEnergyFromState(component);
|
|
} else if (state_manager.state.dataset === 'power' && !state_manager.matchesPowerState()){
|
|
promise = state_manager.setHousePowerFromState(component);
|
|
} else if (state_manager.state.dataset === 'irradiance'){
|
|
promise = state_manager.setIrradianceData(component);
|
|
} else {
|
|
promise = Promise.resolve();
|
|
}
|
|
return promise.then(()=>{
|
|
state_manager.update_in_progress = false;
|
|
return new Promise((fnResolve, fnReject)=>{
|
|
component.syncFromStateManager(fnResolve);
|
|
});
|
|
});
|
|
}
|
|
|
|
setHouseEnergyFromState(component){
|
|
var state_manager = this;
|
|
return new Promise((fnResolve, fnReject)=>{
|
|
component.setState({
|
|
loading_data: 'power'
|
|
}, ()=>{
|
|
state_manager.state.house.setEnergyData(state_manager.year_range)
|
|
.then(fnResolve);
|
|
});
|
|
});
|
|
}
|
|
|
|
setHousePowerFromState(component){
|
|
var state_manager = this,
|
|
house = state_manager.state.house;
|
|
return new Promise((fnResolve, fnReject)=>{
|
|
component.setState({
|
|
loading_data: 'energy'
|
|
}, ()=>{
|
|
house.setPowerData(state_manager.state.date_interval)
|
|
.then(fnResolve);
|
|
});
|
|
});
|
|
}
|
|
|
|
setIrradianceData(component){
|
|
var state_manager = this,
|
|
houses = state_manager.houses,
|
|
date_interval = state_manager.state.date_interval;
|
|
return new Promise((fnResolve, fnReject)=>{
|
|
component.setState({
|
|
loading_data: 'irradiance'
|
|
}, ()=>{
|
|
EnergyDatum.ensureEnergyDataForHouses(houses, date_interval)
|
|
.then((res)=>{
|
|
if (res instanceof Promise){
|
|
throw new Error('promise returned promise')
|
|
}
|
|
var promises = [],
|
|
data = {};
|
|
houses.forEach((house)=>{
|
|
var promise = house.setEnergyData(date_interval)
|
|
.then(()=>{
|
|
house.energy_data.forEach((energy_datum)=>{
|
|
var date_data = data[energy_datum.day_to_s];
|
|
if (!date_data){
|
|
date_data = [];
|
|
data[energy_datum.day_to_s] = date_data;
|
|
}
|
|
date_data.push(energy_datum);
|
|
});
|
|
house.closeDb();
|
|
});
|
|
promises.push(promise);
|
|
});
|
|
Promise.all(promises)
|
|
.then(()=>{
|
|
state_manager.irradiance_data = data;
|
|
fnResolve();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
/*
|
|
* Change Params -> Change Url
|
|
*/
|
|
|
|
setParams(params){
|
|
var state_manager = this,
|
|
url, house, params;
|
|
if (state_manager.update_in_progress) return false;
|
|
state_manager.update_in_progress = true;
|
|
|
|
params = Object.assign({}, state_manager.state, params);
|
|
if (params.house_id){
|
|
house = state_manager.houses.find((h)=>{ return h.data.id == params.house_id; });
|
|
} else {
|
|
house = state_manager.state.house || state_manager.houses[0];
|
|
params.house_id = house.data.id;
|
|
}
|
|
|
|
house.verifyMonthState(params);
|
|
if (params.dataset === 'irradiance'){
|
|
params.date_interval = house.verifyPowerRange(params.date_interval || [], params);
|
|
url = `/irradiance/${params.month}/${params.year}/${params.view}?${query_string.stringify({dates: params.date_interval})}`;
|
|
} else if (params.dataset === 'energy'){
|
|
url = `/houses/${params.house_id}/energy/${params.year}/${params.graph_attr}/${params.view}`;
|
|
} else {
|
|
params.date_interval = house.verifyPowerRange(params.date_interval || [], params);
|
|
url = `/houses/${params.house_id}/power/${params.month}/${params.year}/${params.view}?${query_string.stringify({dates: params.date_interval})}`;
|
|
}
|
|
|
|
state_manager.history.push(url);
|
|
}
|
|
|
|
/*
|
|
* Url Changed -> Change State
|
|
*/
|
|
|
|
updateStateFromUrl(location, component){
|
|
var state_manager = this,
|
|
params = state_manager.parseUrl(location.pathname),
|
|
house = null;
|
|
if (params.house_id){
|
|
house = state_manager.houses.find((h)=>{ return h.data.id == params.house_id; });
|
|
} else if (params.dataset === 'irradiance'){
|
|
// Irradiance needs a house to verify params and
|
|
house = state_manager.state.house || state_manager.houses[0];
|
|
}
|
|
|
|
if (house){
|
|
// params should already be verified if set through StateManager#setParams, but
|
|
// verify here again before setting state in case URL manually loaded.
|
|
house.verifyMonthState(params);
|
|
if (params.dataset === 'power' || params.dataset === 'irradiance') {
|
|
var date_interval = location.query.dates || [];
|
|
params.date_interval = house.verifyPowerRange([+date_interval[0], +date_interval[1]], params);
|
|
}
|
|
state_manager.state.house = house;
|
|
state_manager.state.house_id = house.data.id;
|
|
}
|
|
|
|
Object.assign(state_manager.state, params);
|
|
if (state_manager.state.house_id) {
|
|
state_manager.updateHouseFromState(component);
|
|
} else {
|
|
component.syncFromStateManager(()=>{
|
|
state_manager.update_in_progress = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
parseUrl(url, query){
|
|
for (var route of ROUTES){
|
|
var match = url.match(route.path);
|
|
if (match){
|
|
var parsed = {};
|
|
for (var index in route.parameters){
|
|
parsed[route.parameters[index]] = match[index];
|
|
}
|
|
return parsed;
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
}
|
|
|
|
export default StateManager;
|