PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/src/net/sacredlabyrinth/phaed/simpleclans/ChatBlock.java

https://github.com/masp/SimpleClans
Java | 840 lines | 499 code | 131 blank | 210 comment | 119 complexity | 5c7539c114c9647609e3b7951cc6cbbd MD5 | raw file
  1. package net.sacredlabyrinth.phaed.simpleclans;
  2. import java.util.Arrays;
  3. import org.bukkit.entity.Player;
  4. import org.bukkit.ChatColor;
  5. import java.util.ArrayList;
  6. import java.util.LinkedList;
  7. import java.util.List;
  8. import java.util.logging.Logger;
  9. import java.util.regex.*;
  10. /**
  11. *
  12. * @author phaed
  13. */
  14. public class ChatBlock
  15. {
  16. private static final int lineLength = 319;
  17. private ArrayList<Boolean> columnFlexes = new ArrayList<Boolean>();
  18. private ArrayList<Integer> columnSizes = new ArrayList<Integer>();
  19. private ArrayList<String> columnAlignments = new ArrayList<String>();
  20. private LinkedList<String[]> rows = new LinkedList<String[]>();
  21. private String color = "";
  22. /**
  23. *
  24. */
  25. public static final Logger log = Logger.getLogger("Minecraft");
  26. /**
  27. *
  28. * @param columnAlignment
  29. */
  30. public void setAlignment(String... columnAlignment)
  31. {
  32. columnAlignments.addAll(Arrays.asList(columnAlignment));
  33. }
  34. /**
  35. *
  36. * @param columnFlex
  37. */
  38. public void setFlexibility(boolean... columnFlex)
  39. {
  40. for (boolean flex : columnFlex)
  41. {
  42. columnFlexes.add(flex);
  43. }
  44. }
  45. /**
  46. *
  47. * @param columnPercentages
  48. * @param prefix
  49. */
  50. public void setColumnSizes(String prefix, double... columnPercentages)
  51. {
  52. int ll = lineLength;
  53. if (prefix != null)
  54. {
  55. ll = lineLength - (int) msgLength(prefix);
  56. }
  57. for (double percentage : columnPercentages)
  58. {
  59. columnSizes.add((int) Math.floor((percentage / 100) * ll));
  60. }
  61. }
  62. /**
  63. *
  64. * @return
  65. */
  66. public boolean hasContent()
  67. {
  68. return rows.size() > 0;
  69. }
  70. /**
  71. *
  72. * @param contents
  73. */
  74. public void addRow(String... contents)
  75. {
  76. rows.add(contents);
  77. }
  78. /**
  79. *
  80. * @return
  81. */
  82. public int size()
  83. {
  84. return rows.size();
  85. }
  86. /**
  87. *
  88. * @return
  89. */
  90. public boolean isEmpty()
  91. {
  92. return rows.size() == 0;
  93. }
  94. /**
  95. *
  96. */
  97. public void clear()
  98. {
  99. rows.clear();
  100. }
  101. /**
  102. *
  103. * @param player
  104. * @return
  105. */
  106. public boolean sendBlock(Player player)
  107. {
  108. return sendBlock(player, null, 0);
  109. }
  110. /**
  111. *
  112. * @param player
  113. * @param prefix
  114. * @return
  115. */
  116. public boolean sendBlock(Player player, String prefix)
  117. {
  118. return sendBlock(player, prefix, 0);
  119. }
  120. /**
  121. *
  122. * @param player
  123. * @param amount
  124. * @return
  125. */
  126. public boolean sendBlock(Player player, int amount)
  127. {
  128. return sendBlock(player, null, amount);
  129. }
  130. /**
  131. *
  132. * @param player
  133. * @param prefix
  134. * @param amount
  135. * @return
  136. */
  137. boolean sendBlock(Player player, String prefix, int amount)
  138. {
  139. if (player == null)
  140. {
  141. return false;
  142. }
  143. if (rows.size() == 0)
  144. {
  145. return false;
  146. }
  147. if (amount == 0)
  148. {
  149. amount = rows.size();
  150. }
  151. boolean prefix_used = prefix == null;
  152. String empty_prefix = ChatBlock.makeEmpty(prefix);
  153. // if no column sizes provided then
  154. // make some up based on the data
  155. if (columnSizes.isEmpty())
  156. {
  157. // generate columns sizes
  158. for (int i = 0; i < rows.get(0).length; i++)
  159. {
  160. columnSizes.add(getMaxWidth(i) + 4);
  161. }
  162. }
  163. // size up all sections
  164. for (int i = 0; i < amount; i++)
  165. {
  166. if (rows.size() == 0)
  167. {
  168. continue;
  169. }
  170. List<String> measuredCols = new ArrayList<String>();
  171. String row[] = rows.pollFirst();
  172. for (int sid = 0; sid < row.length; sid++)
  173. {
  174. String col = "";
  175. String section = row[sid];
  176. double colsize = (columnSizes.size() >= (sid + 1)) ? columnSizes.get(sid) : 0;
  177. String align = (columnAlignments.size() >= (sid + 1)) ? columnAlignments.get(sid) : "l";
  178. if (align.equalsIgnoreCase("r"))
  179. {
  180. if (msgLength(section) > colsize)
  181. {
  182. col = cropLeftToFit(section, colsize);
  183. }
  184. else if (msgLength(section) < colsize)
  185. {
  186. col = paddLeftToFit(section, colsize);
  187. }
  188. }
  189. else if (align.equalsIgnoreCase("l"))
  190. {
  191. if (msgLength(section) > colsize)
  192. {
  193. col = cropRightToFit(section, colsize);
  194. }
  195. else if (msgLength(section) < colsize)
  196. {
  197. col = paddRightToFit(section, colsize);
  198. }
  199. }
  200. else if (align.equalsIgnoreCase("c"))
  201. {
  202. if (msgLength(section) > colsize)
  203. {
  204. col = cropRightToFit(section, colsize);
  205. }
  206. else if (msgLength(section) < colsize)
  207. {
  208. col = centerInLineOf(section, colsize);
  209. }
  210. }
  211. measuredCols.add(col);
  212. }
  213. // add in spacings
  214. int colspacing = 12;
  215. int availableSpacing = colspacing;
  216. while (calculatedRowSize(measuredCols) < lineLength && availableSpacing > 0)
  217. {
  218. for (int j = 0; j < measuredCols.size(); j++)
  219. {
  220. String col = measuredCols.get(j);
  221. measuredCols.set(j, col + " ");
  222. if (calculatedRowSize(measuredCols) >= lineLength)
  223. {
  224. break;
  225. }
  226. }
  227. availableSpacing -= 4;
  228. }
  229. // cut off from flexible columns if too big
  230. if (columnFlexes.size() == measuredCols.size())
  231. {
  232. while (calculatedRowSize(measuredCols) > lineLength)
  233. {
  234. boolean didFlex = false;
  235. for (int j = 0; j < measuredCols.size(); j++)
  236. {
  237. boolean flex = columnFlexes.get(j);
  238. if (flex)
  239. {
  240. String col = measuredCols.get(j);
  241. if (col.length() > 0)
  242. {
  243. measuredCols.set(j, col.substring(0, col.length() - 1));
  244. didFlex = true;
  245. }
  246. }
  247. if (calculatedRowSize(measuredCols) <= lineLength)
  248. {
  249. break;
  250. }
  251. }
  252. if (!didFlex)
  253. {
  254. break;
  255. }
  256. }
  257. }
  258. // concatenate final strings
  259. String finalString = "";
  260. for (String measured : measuredCols)
  261. {
  262. finalString += measured;
  263. }
  264. // crop and print out
  265. String msg = cropRightToFit((prefix_used ? empty_prefix : prefix + " ") + finalString, lineLength);
  266. if (color.length() > 0)
  267. {
  268. msg = color + msg;
  269. }
  270. player.sendMessage(msg);
  271. prefix_used = true;
  272. }
  273. return rows.size() > 0;
  274. }
  275. private int calculatedRowSize(List<String> cols)
  276. {
  277. int out = 0;
  278. for (String col : cols)
  279. {
  280. out += msgLength(col);
  281. }
  282. return out;
  283. }
  284. /**
  285. *
  286. * @param col
  287. * @return
  288. */
  289. int getMaxWidth(int col)
  290. {
  291. double maxWidth = 0;
  292. for (String[] row : rows)
  293. {
  294. maxWidth = Math.max(maxWidth, msgLength(row[col]));
  295. }
  296. return (int) maxWidth;
  297. }
  298. /**
  299. *
  300. * @param msg
  301. * @return
  302. */
  303. public static String centerInLine(String msg)
  304. {
  305. return centerInLineOf(msg, lineLength);
  306. }
  307. /**
  308. *
  309. * @param msg
  310. * @param lineLength
  311. * @return
  312. */
  313. private static String centerInLineOf(String msg, double lineLength)
  314. {
  315. double length = msgLength(msg);
  316. double diff = lineLength - length;
  317. // if too big for line return it as is
  318. if (diff < 0)
  319. {
  320. return msg;
  321. }
  322. double sideSpace = diff / 2;
  323. // pad the left with space
  324. msg = paddLeftToFit(msg, lineLength - Math.floor(sideSpace));
  325. // padd the right with space
  326. msg = paddRightToFit(msg, lineLength);
  327. return msg;
  328. }
  329. /**
  330. *
  331. * @param str
  332. * @return
  333. */
  334. public static String makeEmpty(String str)
  335. {
  336. if (str == null)
  337. {
  338. return "";
  339. }
  340. return paddLeftToFit("", msgLength(str));
  341. }
  342. /**
  343. *
  344. * @param msg
  345. * @param length
  346. * @return
  347. */
  348. private static String cropRightToFit(String msg, double length)
  349. {
  350. if (msg == null || msg.length() == 0 || length == 0)
  351. {
  352. return "";
  353. }
  354. while (msgLength(msg) > length)
  355. {
  356. msg = msg.substring(0, msg.length() - 2);
  357. }
  358. return msg;
  359. }
  360. /**
  361. *
  362. * @param msg
  363. * @param length
  364. * @return
  365. */
  366. private static String cropLeftToFit(String msg, double length)
  367. {
  368. if (msg == null || msg.length() == 0 || length == 0)
  369. {
  370. return "";
  371. }
  372. while (msgLength(msg) >= length)
  373. {
  374. msg = msg.substring(1);
  375. }
  376. return msg;
  377. }
  378. /**
  379. * Padds left til the string is a certain size
  380. * @param msg
  381. * @param length
  382. * @return
  383. */
  384. private static String paddLeftToFit(String msg, double length)
  385. {
  386. if (msgLength(msg) >= length)
  387. {
  388. return msg;
  389. }
  390. while (msgLength(msg) < length)
  391. {
  392. msg = " " + msg;
  393. }
  394. return msg;
  395. }
  396. /**
  397. * Padds right til the string is a certain size
  398. * @param msg
  399. * @param length
  400. * @return
  401. */
  402. private static String paddRightToFit(String msg, double length)
  403. {
  404. if (msgLength(msg) >= length)
  405. {
  406. return msg;
  407. }
  408. while (msgLength(msg) < length)
  409. {
  410. msg += " ";
  411. }
  412. return msg;
  413. }
  414. /**
  415. * Finds the length on the screen of a string. Ignores colors.
  416. * @param str
  417. * @return
  418. */
  419. private static double msgLength(String str)
  420. {
  421. double length = 0;
  422. str = cleanColors(str);
  423. // Loop through all the characters, skipping any color characters and their following color codes
  424. for (int x = 0; x < str.length(); x++)
  425. {
  426. int len = charLength(str.charAt(x));
  427. if (len > 0)
  428. {
  429. length += len;
  430. }
  431. else
  432. {
  433. x++;
  434. }
  435. }
  436. return length;
  437. }
  438. /**
  439. *
  440. * @param str
  441. * @return
  442. */
  443. private static String cleanColors(String str)
  444. {
  445. String patternStr = "�.";
  446. String replacementStr = "";
  447. Pattern pattern = Pattern.compile(patternStr);
  448. Matcher matcher = pattern.matcher(str);
  449. return matcher.replaceAll(replacementStr);
  450. }
  451. /**
  452. * Finds the visual length of the character on the screen.
  453. * @param x
  454. * @return
  455. */
  456. private static int charLength(char x)
  457. {
  458. if ("i.:,;|!".indexOf(x) != -1)
  459. {
  460. return 2;
  461. }
  462. else if ("l'".indexOf(x) != -1)
  463. {
  464. return 3;
  465. }
  466. else if ("tI[]".indexOf(x) != -1)
  467. {
  468. return 4;
  469. }
  470. else if ("fk{}<>\"*()".indexOf(x) != -1)
  471. {
  472. return 5;
  473. }
  474. else if ("abcdeghjmnopqrsuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890\\/#?$%-=_+&^".indexOf(x) != -1)
  475. {
  476. return 6;
  477. }
  478. else if ("@~".indexOf(x) != -1)
  479. {
  480. return 7;
  481. }
  482. else if (x == ' ')
  483. {
  484. return 4;
  485. }
  486. else
  487. {
  488. return -1;
  489. }
  490. }
  491. /**
  492. * Cuts the message apart into whole words short enough to fit on one line
  493. * @param msg
  494. * @return
  495. */
  496. private static String[] wordWrap(String msg)
  497. {
  498. // Split each word apart
  499. ArrayList<String> split = new ArrayList<String>();
  500. split.addAll(Arrays.asList(msg.split(" ")));
  501. // Create an array list for the output
  502. ArrayList<String> out = new ArrayList<String>();
  503. // While i is less than the length of the array of words
  504. while (!split.isEmpty())
  505. {
  506. int len = 0;
  507. // Create an array list to hold individual words
  508. ArrayList<String> words = new ArrayList<String>();
  509. // Loop through the words finding their length and increasing
  510. // j, the end point for the sub string
  511. while (!split.isEmpty() && split.get(0) != null && len <= lineLength)
  512. {
  513. double wordLength = msgLength(split.get(0)) + 4;
  514. // If a word is too long for a line
  515. if (wordLength > lineLength)
  516. {
  517. String[] tempArray = wordCut(len, split.remove(0));
  518. words.add(tempArray[0]);
  519. split.add(tempArray[1]);
  520. }
  521. // If the word is not too long to fit
  522. len += wordLength;
  523. if (len < lineLength)
  524. {
  525. words.add(split.remove(0));
  526. }
  527. }
  528. // Merge them and add them to the output array.
  529. String merged = combineSplit(words.toArray(new String[words.size()])) + " ";
  530. out.add(merged.replaceAll("\\s+$", ""));
  531. }
  532. // Convert to an array and return
  533. return out.toArray(new String[out.size()]);
  534. }
  535. /**
  536. *
  537. *
  538. *
  539. * @param string
  540. * @return
  541. */
  542. private static String combineSplit(String[] string)
  543. {
  544. StringBuilder builder = new StringBuilder();
  545. for (String aString : string)
  546. {
  547. builder.append(aString);
  548. builder.append(" ");
  549. }
  550. builder.deleteCharAt(builder.length() - " ".length());
  551. return builder.toString();
  552. }
  553. /**
  554. * Cuts apart a word that is too long to fit on one line
  555. * @param lengthBefore
  556. * @param str
  557. * @return
  558. */
  559. private static String[] wordCut(int lengthBefore, String str)
  560. {
  561. int length = lengthBefore;
  562. // Loop through all the characters, skipping any color characters and their following color codes
  563. String[] output = new String[2];
  564. int x = 0;
  565. while (length < lineLength && x < str.length())
  566. {
  567. int len = charLength(str.charAt(x));
  568. if (len > 0)
  569. {
  570. length += len;
  571. }
  572. else
  573. {
  574. x++;
  575. }
  576. x++;
  577. }
  578. if (x > str.length())
  579. {
  580. x = str.length();
  581. }
  582. // Add the substring to the output after cutting it
  583. output[0] = str.substring(0, x);
  584. // Add the last of the string to the output.
  585. output[1] = str.substring(x);
  586. return output;
  587. }
  588. /**
  589. * Outputs a single line out, crops overflow
  590. * @param receiver
  591. * @param msg
  592. */
  593. public static void saySingle(Player receiver, String msg)
  594. {
  595. if (receiver == null)
  596. {
  597. return;
  598. }
  599. receiver.sendMessage(colorize(new String[] {cropRightToFit(msg, lineLength)})[0]);
  600. }
  601. /**
  602. * Outputs a message to a user
  603. * @param receiver
  604. * @param msg
  605. */
  606. public static void sendMessage(Player receiver, String msg)
  607. {
  608. if (receiver == null)
  609. {
  610. return;
  611. }
  612. String[] message = colorize(wordWrap(msg));
  613. for (String out : message)
  614. {
  615. receiver.sendMessage(out);
  616. }
  617. }
  618. /**
  619. * Send blank lie
  620. * @param color
  621. */
  622. public void startColor(String color)
  623. {
  624. this.color = color;
  625. }
  626. /**
  627. * Send blank lie
  628. * @param receiver
  629. */
  630. public static void sendBlank(Player receiver)
  631. {
  632. if (receiver == null)
  633. {
  634. return;
  635. }
  636. receiver.sendMessage(" ");
  637. }
  638. /**
  639. * Colors each line
  640. * @param message
  641. * @return
  642. */
  643. public static String[] say(String message)
  644. {
  645. return colorize(wordWrap(message));
  646. }
  647. /**
  648. *
  649. * @param message
  650. * @return
  651. */
  652. private static String[] colorize(String[] message)
  653. {
  654. return colorizeBase(message);
  655. }
  656. /**
  657. *
  658. * @param message
  659. * @return
  660. */
  661. public static String colorize(String message)
  662. {
  663. return colorizeBase((new String[]
  664. {
  665. message
  666. }))[0];
  667. }
  668. /**
  669. *
  670. *
  671. * @param message
  672. * @return
  673. */
  674. private static String[] colorizeBase(String[] message)
  675. {
  676. if (message != null && message[0] != null && !message[0].isEmpty())
  677. {
  678. // Go through each line
  679. String prevColor = "";
  680. String lastColor = "";
  681. int counter = 0;
  682. for (String msg : message)
  683. {
  684. // Loop through looking for a color code
  685. for (int x = 0; x < msg.length(); x++)
  686. {
  687. // If the char is color code
  688. if (msg.codePointAt(x) == 167)
  689. {
  690. // advance x to the next character
  691. x += 1;
  692. try
  693. {
  694. lastColor = ChatColor.getByCode(Integer.parseInt(msg.charAt(x) + "", 16)) + "";
  695. }
  696. catch (Exception ignored)
  697. {
  698. }
  699. }
  700. }
  701. // Replace the message with the colorful message
  702. message[counter] = prevColor + msg;
  703. prevColor = lastColor;
  704. counter++;
  705. }
  706. }
  707. return message;
  708. }
  709. }