1var Hack = require('./hack');
2
3var Marker = require('../tokenizer/marker');
4var Token = require('../tokenizer/token');
5
6var Match = {
7  ASTERISK: '*',
8  BACKSLASH: '\\',
9  BANG: '!',
10  BANG_SUFFIX_PATTERN: /!\w+$/,
11  IMPORTANT_TOKEN: '!important',
12  IMPORTANT_TOKEN_PATTERN: new RegExp('!important$', 'i'),
13  IMPORTANT_WORD: 'important',
14  IMPORTANT_WORD_PATTERN: new RegExp('important$', 'i'),
15  SUFFIX_BANG_PATTERN: /!$/,
16  UNDERSCORE: '_',
17  VARIABLE_REFERENCE_PATTERN: /var\(--.+\)$/
18};
19
20function wrapAll(properties, includeVariable, skipProperties) {
21  var wrapped = [];
22  var single;
23  var property;
24  var i;
25
26  for (i = properties.length - 1; i >= 0; i--) {
27    property = properties[i];
28
29    if (property[0] != Token.PROPERTY) {
30      continue;
31    }
32
33    if (!includeVariable && someVariableReferences(property)) {
34      continue;
35    }
36
37    if (skipProperties && skipProperties.indexOf(property[1][1]) > -1) {
38      continue;
39    }
40
41    single = wrapSingle(property);
42    single.all = properties;
43    single.position = i;
44    wrapped.unshift(single);
45  }
46
47  return wrapped;
48}
49
50function someVariableReferences(property) {
51  var i, l;
52  var value;
53
54  // skipping `property` and property name tokens
55  for (i = 2, l = property.length; i < l; i++) {
56    value = property[i];
57
58    if (value[0] != Token.PROPERTY_VALUE) {
59      continue;
60    }
61
62    if (isVariableReference(value[1])) {
63      return true;
64    }
65  }
66
67  return false;
68}
69
70function isVariableReference(value) {
71  return Match.VARIABLE_REFERENCE_PATTERN.test(value);
72}
73
74function isMultiplex(property) {
75  var value;
76  var i, l;
77
78  for (i = 3, l = property.length; i < l; i++) {
79    value = property[i];
80
81    if (value[0] == Token.PROPERTY_VALUE && (value[1] == Marker.COMMA || value[1] == Marker.FORWARD_SLASH)) {
82      return true;
83    }
84  }
85
86  return false;
87}
88
89function hackFrom(property) {
90  var match = false;
91  var name = property[1][1];
92  var lastValue = property[property.length - 1];
93
94  if (name[0] == Match.UNDERSCORE) {
95    match = [Hack.UNDERSCORE];
96  } else if (name[0] == Match.ASTERISK) {
97    match = [Hack.ASTERISK];
98  } else if (lastValue[1][0] == Match.BANG && !lastValue[1].match(Match.IMPORTANT_WORD_PATTERN)) {
99    match = [Hack.BANG];
100  } else if (lastValue[1].indexOf(Match.BANG) > 0 && !lastValue[1].match(Match.IMPORTANT_WORD_PATTERN) && Match.BANG_SUFFIX_PATTERN.test(lastValue[1])) {
101    match = [Hack.BANG];
102  } else if (lastValue[1].indexOf(Match.BACKSLASH) > 0 && lastValue[1].indexOf(Match.BACKSLASH) == lastValue[1].length - Match.BACKSLASH.length - 1) {
103    match = [Hack.BACKSLASH, lastValue[1].substring(lastValue[1].indexOf(Match.BACKSLASH) + 1)];
104  } else if (lastValue[1].indexOf(Match.BACKSLASH) === 0 && lastValue[1].length == 2) {
105    match = [Hack.BACKSLASH, lastValue[1].substring(1)];
106  }
107
108  return match;
109}
110
111function isImportant(property) {
112  if (property.length < 3)
113    return false;
114
115  var lastValue = property[property.length - 1];
116  if (Match.IMPORTANT_TOKEN_PATTERN.test(lastValue[1])) {
117    return true;
118  } else if (Match.IMPORTANT_WORD_PATTERN.test(lastValue[1]) && Match.SUFFIX_BANG_PATTERN.test(property[property.length - 2][1])) {
119    return true;
120  }
121
122  return false;
123}
124
125function stripImportant(property) {
126  var lastValue = property[property.length - 1];
127  var oneButLastValue = property[property.length - 2];
128
129  if (Match.IMPORTANT_TOKEN_PATTERN.test(lastValue[1])) {
130    lastValue[1] = lastValue[1].replace(Match.IMPORTANT_TOKEN_PATTERN, '');
131  } else {
132    lastValue[1] = lastValue[1].replace(Match.IMPORTANT_WORD_PATTERN, '');
133    oneButLastValue[1] = oneButLastValue[1].replace(Match.SUFFIX_BANG_PATTERN, '');
134  }
135
136  if (lastValue[1].length === 0) {
137    property.pop();
138  }
139
140  if (oneButLastValue[1].length === 0) {
141    property.pop();
142  }
143}
144
145function stripPrefixHack(property) {
146  property[1][1] = property[1][1].substring(1);
147}
148
149function stripSuffixHack(property, hackFrom) {
150  var lastValue = property[property.length - 1];
151  lastValue[1] = lastValue[1]
152    .substring(0, lastValue[1].indexOf(hackFrom[0] == Hack.BACKSLASH ? Match.BACKSLASH : Match.BANG))
153    .trim();
154
155  if (lastValue[1].length === 0) {
156    property.pop();
157  }
158}
159
160function wrapSingle(property) {
161  var importantProperty = isImportant(property);
162  if (importantProperty) {
163    stripImportant(property);
164  }
165
166  var whichHack = hackFrom(property);
167  if (whichHack[0] == Hack.ASTERISK || whichHack[0] == Hack.UNDERSCORE) {
168    stripPrefixHack(property);
169  } else if (whichHack[0] == Hack.BACKSLASH || whichHack[0] == Hack.BANG) {
170    stripSuffixHack(property, whichHack);
171  }
172
173  return {
174    block: property[2] && property[2][0] == Token.PROPERTY_BLOCK,
175    components: [],
176    dirty: false,
177    hack: whichHack,
178    important: importantProperty,
179    name: property[1][1],
180    multiplex: property.length > 3 ? isMultiplex(property) : false,
181    position: 0,
182    shorthand: false,
183    unused: false,
184    value: property.slice(2)
185  };
186}
187
188module.exports = {
189  all: wrapAll,
190  single: wrapSingle
191};
192