001package com.hfg.xml.msofficexml;
002
003import java.awt.Color;
004import java.io.Writer;
005import java.util.Comparator;
006import java.util.List;
007import java.util.Map;
008import java.util.Set;
009import java.util.UUID;
010import java.util.logging.Level;
011import java.util.logging.Logger;
012
013import com.hfg.util.collection.CollectionUtil;
014import com.hfg.util.CompareUtil;
015import com.hfg.util.StringUtil;
016import com.hfg.xml.XMLName;
017import com.hfg.xml.XMLNamespaceSet;
018import com.hfg.xml.XMLNode;
019import com.hfg.xml.XMLTag;
020import com.hfg.xml.XMLizable;
021import com.hfg.xml.xsd.XsdElement;
022
023//------------------------------------------------------------------------------
024/**
025 Base tag class for Office Open XML tags.
026
027 @author J. Alex Taylor, hairyfatguy.com
028 */
029//------------------------------------------------------------------------------
030// com.hfg XML/HTML Coding Library
031//
032// This library is free software; you can redistribute it and/or
033// modify it under the terms of the GNU Lesser General Public
034// License as published by the Free Software Foundation; either
035// version 2.1 of the License, or (at your option) any later version.
036//
037// This library is distributed in the hope that it will be useful,
038// but WITHOUT ANY WARRANTY; without even the implied warranty of
039// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
040// Lesser General Public License for more details.
041//
042// You should have received a copy of the GNU Lesser General Public
043// License along with this library; if not, write to the Free Software
044// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
045//
046// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com
047// jataylor@hairyfatguy.com
048//------------------------------------------------------------------------------
049
050public abstract class OfficeOpenXMLTag extends XMLTag implements Cloneable
051{
052   private OfficeOpenXmlDocument mParentDoc;
053
054   public static Level sSQLLoggingLevel = Level.FINE;
055
056   private final static Logger LOGGER = Logger.getLogger(OfficeXML.class.getPackage().getName());
057
058   //###########################################################################
059   // CONSTRUCTORS
060   //###########################################################################
061
062   //---------------------------------------------------------------------------
063   public OfficeOpenXMLTag(XMLName inName, OfficeOpenXmlDocument inParentDoc)
064   {
065      super(inName);
066      mParentDoc = inParentDoc;
067   }
068
069   //###########################################################################
070   // PUBLIC METHODS
071   //###########################################################################
072
073   //---------------------------------------------------------------------------
074   public static Logger getLogger()
075   {
076      return LOGGER;
077   }
078
079   //--------------------------------------------------------------------------
080   /**
081    Converts a Color object in to a hex string as Alpha Red Green Blue.
082    */
083   public static String colorToCT_Color(Color inColor)
084   {
085      String outString = null;
086
087      if (inColor != null)
088      {
089         String alpha = Integer.toHexString(inColor.getAlpha());
090         String red   = Integer.toHexString(inColor.getRed());
091         String green = Integer.toHexString(inColor.getGreen());
092         String blue  = Integer.toHexString(inColor.getBlue());
093
094         if (alpha.length() == 1) alpha = "0" + alpha;
095         if (red.length() == 1)   red   = "0" + red;
096         if (green.length() == 1) green = "0" + green;
097         if (blue.length() == 1)  blue  = "0" + blue;
098
099         outString = (alpha + red + green + blue).toUpperCase();
100      }
101
102      return outString;
103   }
104   //---------------------------------------------------------------------------
105   public OfficeOpenXmlDocument getParentDoc()
106   {
107      return mParentDoc;
108   }
109
110   //---------------------------------------------------------------------------
111   public void setParentDoc(OfficeOpenXmlDocument inValue)
112   {
113      mParentDoc = inValue;
114      for (XMLizable subtag : getSubtags())
115      {
116         if (subtag instanceof OfficeOpenXMLTag)
117         {
118            ((OfficeOpenXMLTag) subtag).setParentDoc(inValue);
119         }
120      }
121   }
122
123
124   //---------------------------------------------------------------------------
125   @Override
126   public void toIndentedXML(Writer inWriter, int inInitialIndentSize, int inIndentSize,
127                             XMLNamespaceSet inDeclaredNamespaces)
128   {
129      // Before writing to XML, be sure the subtags are in the proper sequence.
130      orderSubtags();
131
132      super.toIndentedXML(inWriter, inInitialIndentSize, inIndentSize, inDeclaredNamespaces);
133   }
134
135   //---------------------------------------------------------------------------
136   @Override
137   protected void toXML(Writer inWriter, XMLNamespaceSet inDeclaredNamespaces)
138   {
139      // Before writing to XML, be sure the subtags are in the proper sequence.
140      orderSubtags();
141
142      super.toXML(inWriter, inDeclaredNamespaces);
143   }
144
145   //---------------------------------------------------------------------------
146   // Microsoft is VERY particular about the order of XML tags. We use the DTD to get the ordering correct.
147   protected void orderSubtags()
148   {
149      if (CollectionUtil.hasValues(mContentAndSubtagList)
150          && mContentAndSubtagList.size() > 1)
151      {
152         Set<XsdElement> xsdElements = OfficeOpenXmlXsd.getInstance().getElements(getQualifiedTagName());
153         if (xsdElements != null)
154         {
155            for (XsdElement xsdElement : xsdElements)
156            {
157               mContentAndSubtagList.sort(new XsdSubtagComparator(xsdElement));
158            }
159         }
160         else if (getTagName() != null)
161         {
162            System.out.println("No XsdElement for " + StringUtil.singleQuote(getTagName()));
163         }
164      }
165   }
166
167   //---------------------------------------------------------------------------
168   protected static String generateUID()
169   {
170      return "{" + UUID.randomUUID() + "}";
171   }
172
173
174   //###########################################################################
175   // INNER CLASS
176   //###########################################################################
177
178   private class XsdSubtagComparator implements Comparator<XMLNode>
179   {
180      private Map<String, List<Integer>> mSubtagIndexMap;
181
182      //------------------------------------------------------------------------
183      public XsdSubtagComparator(XsdElement inXsdElement)
184      {
185         mSubtagIndexMap = inXsdElement.getSubtagIndexMap();
186      }
187
188      //------------------------------------------------------------------------
189      public int compare(XMLNode inNode1, XMLNode inNode2)
190      {
191         int result = 0;
192
193         if (inNode1.getTagName() != null
194             && inNode2.getTagName() != null
195             && ! inNode1.getTagName().equals(inNode2.getTagName())) // No need to compare tags of the same name
196         {
197            List<Integer> index1 = getSubtagIndex(inNode1.getTagName());
198            List<Integer> index2 = getSubtagIndex(inNode2.getTagName());
199
200            if (index1 != null)
201            {
202               if (index2 != null)
203               {
204                  for (int i = 0; i < index1.size() && i < index2.size() && 0 == result; i++)
205                  {
206                     result = CompareUtil.compare(index1.get(i), index2.get(i));
207                  }
208               }
209               else
210               {
211                  result = -1;
212               }
213            }
214            else if (index2 != null)
215            {
216               result = 1;
217            }
218
219            if (LOGGER.isLoggable(sSQLLoggingLevel))
220            {
221               LOGGER.log(sSQLLoggingLevel, "Sorting subtag " + inNode1.getTagName() + "  vs.  " + inNode2.getTagName() + ": " + result);
222            }
223         }
224
225
226         return result;
227      }
228
229      //------------------------------------------------------------------------
230      private List<Integer> getSubtagIndex(String inSubtagName)
231      {
232         List<Integer> index = null;
233         if (mSubtagIndexMap != null)
234         {
235            index = mSubtagIndexMap.get(inSubtagName);
236         }
237
238         return index != null ? index : null;
239      }
240
241   }
242
243}