import _ from 'lodash';
import {
  ADD_MODULE,
  REMOVE_MODULE,

  LOAD_THEME,
} from '../constants';

const defaultThemeState = {
  // Theme is defined in `themes.scss`
  theme: 'default',
  // Mapping of module to color index [0-7]
  colors: {},
};
const NUM_DIFFERENT_COLORS = 8;

// Returns a new index that is not present in the current color index.
// If there are more than NUM_DIFFERENT_COLORS modules already present,
// will try to balance the color distribution.
function getNewColor(currentColorIndices) {
  function generateInitialIndices() {
    return _.range(NUM_DIFFERENT_COLORS);
  }

  let availableColorIndices = generateInitialIndices();
  currentColorIndices.forEach((index) => {
    availableColorIndices = _.without(availableColorIndices, index);
    if (availableColorIndices.length === 0) {
      availableColorIndices = generateInitialIndices();
    }
  });

  return _.sample(availableColorIndices);
}

function colors(state, action) {
  switch (action.type) {
    case ADD_MODULE:
      return {
        ...state,
        [action.payload.module.code]: getNewColor(_.values(state)),
      };
    case REMOVE_MODULE:
      return _.omit(state, action.payload.code);
    default:
      return state;
  }
}

function theme(state = defaultThemeState, action) {
  switch (action.type) {
    case ADD_MODULE:
    case REMOVE_MODULE:
      return {
        ...state,
        colors: colors(state.colors, action),
      };
    case `${LOAD_THEME}_FULFILLED`:
      return {
        ...state,
        ...action.payload,
      };
    default:
      return state;
  }
}

export default theme;

@@ -58,16 +58,54 @@
 ODULE,%0A%0A
+  LOAD_TIMETABLE,%0A  FETCH_TIMETABLE,%0A%0A
   LOAD_T
@@ -1268,217 +1268,1304 @@
 %0A%7D%0A%0A
-function theme(state = defaultThemeState, action) %7B%0A  switch (action.type) %7B%0A    case ADD_MODULE:%0A    case REMOVE_MODULE:%0A      return %7B%0A        ...state,%0A        colors: colors(state.colors, action),%0A      %7D;
+const maybeAddNewColorForModuleCode = (state, newState) =%3E (moduleCode) =%3E (%0A  newState%5BmoduleCode%5D = state%5BmoduleCode%5D %7C%7C getNewColor(_.values(state))%0A)%0A%0Afunction loadTimetableColor(state, action) %7B%0A  const newState = %7B%7D;%0A  const addColor = maybeAddNewColorForModuleCode(state, newState);%0A  const timetableModules = action.payload.timetable %7C%7C %5B%5D;%0A  timetableModules%0A    .map(tm =%3E tm.ModuleCode)%0A    .forEach(addColor)%0A%0A  return %7B%0A    ...state,%0A    ...newState,%0A  %7D%0A%7D%0A%0Afunction fetchTimetableColor(state, action) %7B%0A  const newState = %7B%7D;%0A  const addColor = maybeAddNewColorForModuleCode(state, newState);%0A  const timetableModules = action.payload.timetableModules %7C%7C %5B%5D;%0A  timetableModules%0A    .map(tm =%3E tm.module && tm.module.code)%0A    .forEach(addColor)%0A%0A  return %7B%0A    ...state,%0A    ...newState,%0A  %7D%0A%7D%0A%0Afunction theme(state = defaultThemeState, action) %7B%0A  switch (action.type) %7B%0A    case ADD_MODULE:%0A    case REMOVE_MODULE:%0A      return %7B%0A        ...state,%0A        colors: colors(state.colors, action),%0A      %7D;%0A    case %60$%7BFETCH_TIMETABLE%7D_FULFILLED%60:%0A      return %7B%0A        ...state,%0A        colors: fetchTimetableColor(state.colors, action)%0A      %7D%0A    case %60$%7BLOAD_TIMETABLE%7D_FULFILLED%60:%0A      return %7B%0A        ...state,%0A        colors: loadTimetableColor(state.colors, action)%0A      %7D
 %0A   

Fix loading colors when fetch/load timetable