1<?php
2
3
4namespace ComboStrap;
5
6
7class Brand
8{
9
10    const NEWSLETTER_BRAND_NAME = "newsletter";
11    const EMAIL_BRAND_NAME = "email";
12
13
14    /**
15     * The brand of the current application/website
16     */
17    public const CURRENT_BRAND = "current";
18    const CANONICAL = "brand";
19    const ABBR_PROPERTY = 'abbr';
20    /**
21     * @var array an array of brand abbreviation as key and their name as value
22     */
23    private static array $BRAND_ABBR;
24
25
26    private $secondaryColor;
27    private $brandUrl;
28
29    /**
30     * @var array
31     */
32    public static array $brandDictionary;
33    /**
34     * @var bool
35     */
36    private bool $unknown = false;
37    /**
38     * @var mixed
39     */
40    private $brandDict;
41
42
43    /**
44     * Brand constructor.
45     * @param string $name
46     */
47    private function __construct(string $name)
48    {
49
50        $this->name = $name;
51
52        /**
53         * Get the brands
54         */
55        $brandDictionary = Brand::getBrandDictionary();
56
57
58        /**
59         * Build the data for the brand
60         */
61        $this->brandDict = $brandDictionary[$this->name] ?? null;
62        switch ($this->name) {
63            case self::CURRENT_BRAND:
64                $this->brandUrl = Site::getBaseUrl();
65                $secondaryColor = Site::getSecondaryColor();
66                if ($secondaryColor !== null) {
67                    // the predicates on the secondary value is to avoid a loop with the the function below
68                    $this->secondaryColor = $secondaryColor->toCssValue();
69                }
70                break;
71            default:
72                if ($this->brandDict !== null) {
73                    $colors = $this->brandDict["colors"] ?? null;
74                    if ($colors !== null) {
75                        $this->secondaryColor = $colors["secondary"];
76                    } else {
77                        $this->secondaryColor = null;
78                    }
79                    $this->brandUrl = $this->brandDict["url"] ?? null;
80                    return;
81                }
82                $this->unknown = true;
83                break;
84        }
85
86    }
87
88    /**
89     * @return string[]
90     */
91    public static function getAllKnownBrandNames(): array
92    {
93
94        $brands = self::getAllBrands();
95        $brandNames = [self::CURRENT_BRAND];
96        foreach ($brands as $brand) {
97            $brandNames[] = $brand->getName();
98            try {
99                $brandNames[] = $brand->getAbbr();
100            } catch (ExceptionNotFound $e) {
101                // ok
102            }
103        }
104        return $brandNames;
105
106    }
107
108
109    /**
110     * @return Brand[]
111     */
112    public static function getAllBrands(): array
113    {
114        $brandDictionary = self::getBrandDictionary();
115        $brands = [];
116        foreach (array_keys($brandDictionary) as $brandName) {
117            $brands[] = self::create($brandName);
118        }
119        return $brands;
120    }
121
122    /**
123     * @param $type - the button type (ie one of {@link BrandButton::TYPE_BUTTONS}
124     * @return array - the brand names that can be used as type in the brand button
125     */
126    public static function getBrandNamesForButtonType($type): array
127    {
128        $brands = self::getAllBrands();
129        $brandNamesForType = [];
130        foreach ($brands as $brand) {
131            if ($brand->supportButtonType($type)) {
132                $brandNamesForType[] = $brand->getName();
133                try {
134                    $brandNamesForType[] = $brand->getAbbr();
135                } catch (ExceptionNotFound $e) {
136                    // ok
137                }
138            }
139        }
140        return $brandNamesForType;
141    }
142
143    /**
144     *
145     */
146    public static function getBrandDictionary(): array
147    {
148        if (!isset(Brand::$brandDictionary)) {
149            try {
150                Brand::$brandDictionary = Dictionary::getFrom("brands");
151            } catch (ExceptionCompile $e) {
152                // Should never happens
153                Brand::$brandDictionary = [];
154                LogUtility::error("We can't load the brands dictionary. Error: " . $e->getMessage(), self::CANONICAL, $e);
155            }
156        }
157        return Brand::$brandDictionary;
158    }
159
160
161    /**
162     * @var string
163     * The name of the brand,
164     * for company, we follow the naming of
165     * https://github.com/ellisonleao/sharer.js
166     */
167    private $name;
168
169
170    public static function create(string $brandName): Brand
171    {
172
173        $brandNameQualified = strtolower($brandName);
174        $brandNameQualified = Brand::getBrandNameFromAbbr($brandNameQualified);
175        $objectIdentifier = self::CANONICAL . "-" . $brandNameQualified;
176        $executionContext = ExecutionContext::getActualOrCreateFromEnv();
177        try {
178            return $executionContext->getRuntimeObject($objectIdentifier);
179        } catch (ExceptionNotFound $e) {
180            $brandObject = new Brand($brandNameQualified);
181            $executionContext->setRuntimeObject($objectIdentifier, $brandObject);
182            return $brandObject;
183        }
184
185    }
186
187    private static function getBrandNameFromAbbr(string $name)
188    {
189        if (!isset(self::$BRAND_ABBR)) {
190            $brandDictionary = self::getBrandDictionary();
191            foreach ($brandDictionary as $brandName => $brandProperties) {
192                $abbr = $brandProperties[self::ABBR_PROPERTY] ?? null;
193                if (empty($abbr)) {
194                    continue;
195                }
196                self::$BRAND_ABBR[$abbr] = $brandName;
197            }
198        }
199        if (isset(self::$BRAND_ABBR[$name])) {
200            return self::$BRAND_ABBR[$name];
201        }
202        return $name;
203
204    }
205
206
207    /**
208     * If the brand name is unknown (ie custom)
209     * @return bool
210     */
211    public function isUnknown(): bool
212    {
213        return $this->unknown;
214
215    }
216
217    public function getName(): string
218    {
219        return $this->name;
220    }
221
222    public function __toString()
223    {
224        if ($this->name === Brand::CURRENT_BRAND) {
225            return $this->name . " (" . Site::getTitle() . ")";
226        }
227        return $this->name;
228    }
229
230    /**
231     * Shared/Follow Url template
232     * the endpoint template url (for sharing and following)
233     * @var string $type - the type of button
234     */
235    public function getWebUrlTemplate(string $type): ?string
236    {
237        if (isset($this->brandDict[$type])) {
238            return $this->brandDict[$type]["web"];
239        }
240        return null;
241    }
242
243    /**
244     * Brand button title
245     * @return string
246     * @var ?string $type - the button type
247     */
248    public function getTitle(string $type = null): ?string
249    {
250        if ($this->name === self::CURRENT_BRAND) {
251            return Site::getTitle();
252        }
253        if ($this->brandDict !== null && $type !== null) {
254            if (isset($this->brandDict[$type])) {
255                return $this->brandDict[$type]["popup"];
256            }
257        }
258        return null;
259
260    }
261
262    public function getPrimaryColor(): ?string
263    {
264
265        if ($this->brandDict !== null) {
266            $primaryColor = $this->brandDict["colors"]["primary"];
267            if ($primaryColor !== null) {
268                return $primaryColor;
269            }
270        }
271
272        // Unknown or current brand / unknown color
273        try {
274            return ExecutionContext::getExecutionContext()
275                ->getConfig()
276                ->getPrimaryColor();
277        } catch (ExceptionNotFound $e) {
278            return null;
279        }
280
281    }
282
283    public function getSecondaryColor(): ?string
284    {
285        return $this->secondaryColor;
286    }
287
288    /**
289     * @param string|null $type - the button type
290     * @return string|null
291     */
292    public function getIconName(?string $type): ?string
293    {
294
295        switch ($this->name) {
296            case self::CURRENT_BRAND:
297                try {
298                    return Site::getLogoAsSvgImage()
299                        ->getWikiId();
300                } catch (ExceptionNotFound $e) {
301                    // no logo installed
302                }
303                break;
304            default:
305                if (isset($this->brandDict["icons"])) {
306                    return $this->brandDict["icons"][$type];
307                }
308                break;
309        }
310
311        return null;
312    }
313
314    public function getBrandUrl(): ?string
315    {
316        return $this->brandUrl;
317    }
318
319    /**
320     */
321    public function supportButtonType(string $type): bool
322    {
323        switch ($type) {
324            case BrandButton::TYPE_BUTTON_SHARE:
325            case BrandButton::TYPE_BUTTON_FOLLOW:
326                if ($this->getWebUrlTemplate($type) !== null) {
327                    return true;
328                }
329                return false;
330            default:
331            case BrandButton::TYPE_BUTTON_BRAND:
332                return true;
333        }
334    }
335
336    /**
337     * @throws ExceptionNotFound
338     */
339    private function getAbbr()
340    {
341        $value = $this->brandDict['abbr'] ?? null;
342        if (empty($value)) {
343            throw new ExceptionNotFound("No abbreviations");
344        }
345        return $value;
346    }
347
348
349}
350