1var canReorder = require('./reorderable').canReorder;
2var canReorderSingle = require('./reorderable').canReorderSingle;
3var extractProperties = require('./extract-properties');
4var rulesOverlap = require('./rules-overlap');
5
6var serializeRules = require('../../writer/one-time').rules;
7var OptimizationLevel = require('../../options/optimization-level').OptimizationLevel;
8var Token = require('../../tokenizer/token');
9
10function mergeMediaQueries(tokens, context) {
11  var mergeSemantically = context.options.level[OptimizationLevel.Two].mergeSemantically;
12  var specificityCache = context.cache.specificity;
13  var candidates = {};
14  var reduced = [];
15
16  for (var i = tokens.length - 1; i >= 0; i--) {
17    var token = tokens[i];
18    if (token[0] != Token.NESTED_BLOCK) {
19      continue;
20    }
21
22    var key = serializeRules(token[1]);
23    var candidate = candidates[key];
24    if (!candidate) {
25      candidate = [];
26      candidates[key] = candidate;
27    }
28
29    candidate.push(i);
30  }
31
32  for (var name in candidates) {
33    var positions = candidates[name];
34
35    positionLoop:
36    for (var j = positions.length - 1; j > 0; j--) {
37      var positionOne = positions[j];
38      var tokenOne = tokens[positionOne];
39      var positionTwo = positions[j - 1];
40      var tokenTwo = tokens[positionTwo];
41
42      directionLoop:
43      for (var direction = 1; direction >= -1; direction -= 2) {
44        var topToBottom = direction == 1;
45        var from = topToBottom ? positionOne + 1 : positionTwo - 1;
46        var to = topToBottom ? positionTwo : positionOne;
47        var delta = topToBottom ? 1 : -1;
48        var source = topToBottom ? tokenOne : tokenTwo;
49        var target = topToBottom ? tokenTwo : tokenOne;
50        var movedProperties = extractProperties(source);
51
52        while (from != to) {
53          var traversedProperties = extractProperties(tokens[from]);
54          from += delta;
55
56          if (mergeSemantically && allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties, specificityCache)) {
57            continue;
58          }
59
60          if (!canReorder(movedProperties, traversedProperties, specificityCache))
61            continue directionLoop;
62        }
63
64        target[2] = topToBottom ?
65          source[2].concat(target[2]) :
66          target[2].concat(source[2]);
67        source[2] = [];
68
69        reduced.push(target);
70        continue positionLoop;
71      }
72    }
73  }
74
75  return reduced;
76}
77
78function allSameRulePropertiesCanBeReordered(movedProperties, traversedProperties, specificityCache) {
79  var movedProperty;
80  var movedRule;
81  var traversedProperty;
82  var traversedRule;
83  var i, l;
84  var j, m;
85
86  for (i = 0, l = movedProperties.length; i < l; i++) {
87    movedProperty = movedProperties[i];
88    movedRule = movedProperty[5];
89
90    for (j = 0, m = traversedProperties.length; j < m; j++) {
91      traversedProperty = traversedProperties[j];
92      traversedRule = traversedProperty[5];
93
94      if (rulesOverlap(movedRule, traversedRule, true) && !canReorderSingle(movedProperty, traversedProperty, specificityCache)) {
95        return false;
96      }
97    }
98  }
99
100  return true;
101}
102
103module.exports = mergeMediaQueries;
104