Type xlsxStyles = Class

    Function Create(sheetobj, file);
    Begin
		sheet_ := sheetobj;
		file_  := file;
		styleXmlFile_ := file_.WorkBook().GetXmlFileObj('xl/styles.xml');
    End

	Function GetStyleId(style);overload;
	Begin
		node := styleXmlFile_.FirstChildElement('styleSheet');
		font_id := insertNode(node, 'fonts', style.Font);
		border_id := insertNode(node, 'borders', style.Border);
		fill_id := insertNode(node, 'fills', style.Fill);

		processNumFmtId(node, 'numFmts', style.NumberFormat);
		numfmt_id := insertNode(node, 'numFmts', style.NumberFormat);

		alignment_marshal := style.Alignment.Marshal();
		if istable(alignment_marshal['children']) or istable(alignment_marshal['attributes']) then
			alignment_flag := 1;
		protection_marshal := style.Protection.Marshal();
		if istable(protection_marshal['children']) or istable(protection_marshal['attributes']) then
			protection_flag := 1;

		xf := TOfficeObj('TXf');
		xf.NumFmtId := style.NumberFormat.NumFmtId ? : 0;
		xf.FontId := font_id;
		xf.FillId := fill_id;
		xf.BorderId := border_id;
		xf.XfId := 0;
		xf.ApplyFont := font_id <> '0' ? 1 : nil;
		xf.ApplyFill := fill_id <> '0' ? 1 : nil;
		xf.ApplyBorder := border_id <> '0' ? 1 : nil;
		xf.ApplyAlignment := alignment_flag ?: nil;
		xf.ApplyProtection := protection_flag ?: nil;
		xf.Alignment := style.Alignment;
		xf.Protection := style.Protection;

		node := node.FirstChildElement('cellXfs');
		count := node.GetAttribute('count');
		node.InsertEndChild(xf.Marshal());
		node.SetAttribute('count', strtoint(count) + 1);
		return count;
	End;

	Function GetStyleId(newStyle, oldStyleId);overload;
	Begin
		if oldStyleId = '' then return nil;
		style_node := styleXmlFile_.FirstChildElement('styleSheet');
		cellXfs_node := style_node.FirstChildElement('cellXfs');
		count := strtoint(cellXfs_node.GetAttribute('count'));
		Id := strtoint(oldStyleId);
		if Id > count-1 then return nil;

		xf := getNode(cellXfs_node, 'xf', Id);
		marshal := xf.marshal()[0];
		xf_node := cellXfs_node.InsertEndChild(marshal);
		cellXfs_node.SetAttribute('count', count + 1);
		attrs := marshal['attributes'];

		style := newStyle;

		numfmt_id := trystrtoint(attrs['numFmtId'], r) ? r : 0;
		copyNode(style_node, xf_node, 'numFmts', 'numFmt', 'numFmtId', numfmt_id, style.NumberFormat);

		font_id := trystrtoint(attrs['fontId'], r) ? r : 0;
		copyNode(style_node, xf_node, 'fonts', 'font', 'fontId', font_id, style.Font);

		border_id := trystrtoint(attrs['borderId'], r) ? r : 0;
		copyNode(style_node, xf_node, 'borders', 'border', 'borderId', border_id, style.Border);

		fill_id := trystrtoint(attrs['fillId'], r) ? r : 0;
		copyNode(style_node, xf_node, 'fills', 'fill', 'fillId', fill_id, style.Fill);

		marshal := style.Alignment.Marshal();
		alignment := xf_node.FirstChildElement('alignment');
		if ifObj(alignment) then class(TSXml).UpdateNode(alignment, marshal['attributes'], marshal['children']);
		else begin
			xf_node.InsertEndChild(marshal);
			xf_node.SetAttribute('applyAlignment', 1);
		end
		marshal := style.Protection.Marshal();
		protection := xf_node.FirstChildElement('protection');
		if ifObj(protection) then class(TSXml).UpdateNode(protection, marshal['attributes'], marshal['children']);
		else begin
			xf_node.InsertEndChild(marshal);
			xf_node.SetAttribute('applyProtection', 1);
		end

		return inttostr(count);
	End;

	Function GetStyle(styleId);
	Begin
		if styleId = '' then return nil;
		style_node := styleXmlFile_.FirstChildElement('styleSheet');
		cellXfs_node := style_node.FirstChildElement('cellXfs');
		count := strtoint(cellXfs_node.GetAttribute('count'));
		Id := strtoint(styleId);
		if Id > count-1 then return nil;

		xf := getNode(cellXfs_node, 'xf', Id);
		attrs := xf.Attributes();
		numfmt_id := trystrtoint(attrs['numFmtId'], r) ? r : 0;
		font_id := trystrtoint(attrs['fontId'], r) ? r : 0;
		border_id := trystrtoint(attrs['borderId'], r) ? r : 0;
		fill_id := trystrtoint(attrs['fillId'], r) ? r : 0;

		alignment := xf.FirstChildElement('alignment');
		protection := xf.FirstChildElement('protection');
		style := TOfficeObj('TStyle');
		numFmts_node := style_node.FirstChildElement('numFmts');
		fonts_node := style_node.FirstChildElement('fonts');
		borders_node := style_node.FirstChildElement('borders');
		fills_node := style_node.FirstChildElement('fills');
		setRootObj(style.NumberFormat, getNode(numFmts_node, 'numFmt', numfmt_id));
		setRootObj(style.Font, getNode(fonts_node, 'font', font_id));
		setRootObj(style.Border, getNode(borders_node, 'border', border_id));
		node := getNode(fills_node, 'fill', fill_id);
		setRootObj(style.Fill, node);
		setFillGradientObj(style.Fill.Gradient, node);
		style.Alignment.RootObj := ifObj(alignment) ? alignment : nil;
		style.Protection.RootObj := ifObj(protection) ? protection : nil;
		setNodeUri(style);
		return style;
	End;

	class Function NewObject(sheetname, file);
	Begin
		o := file.WorkBook().GetSheetObj(sheetname);
		if not ifObj(o) then return 0;
		styles := new xlsxStyles(o, file);
		return styles;
	End;

private

	Function setFillGradientObj(obj, node);
	Begin
		gradient_node := node.FirstChildElement('gradientFill');
		if not ifObj(gradient_node) then return;
		stop_node := gradient_node.FirstChildElement('stop');
		if ifObj(stop_node) then
		begin
			obj.Stop1.RootObj := stop_node;
			obj.Stop1.NodeUri := '';
		end
		stop_node := stop_node.NextElement();
		if ifObj(stop_node) then
		begin
			obj.Stop2.RootObj := stop_node;
			obj.Stop2.NodeUri := '';
		end
		stop_node := stop_node.NextElement();
		if ifObj(stop_node) then
		begin
			obj.Stop3.RootObj := stop_node;
			obj.Stop3.NodeUri := '';
		end
	End;

	Function setRootObj(obj, node);
	Begin
		obj.RootObj := node;
		children := obj.GetChildren();
		for i:=0 to length(children)-1 do
		begin
			val := children[i]['obj'];
			if ifObj(val) then
			begin
				val.NodeUri := children[i]['name'];
				val.RootObj := node;
			end
		end;
	End;

	Function setNodeUri(obj);
	Begin
		obj.NodeUri := '';
		children := obj.GetChildren();
		for i:=0 to length(children)-1 do
		begin
			val := children[i]['obj'];
			if ifObj(val) then val.NodeUri := '';
		end;
	End;

	Function getNode(rootNode, name, count);
	Begin
		if name = 'numFmt' then return getNodeNumFmts(rootNode, count);
		if not ifObj(rootNode) then return nil;
		node := rootNode.FirstChildElement(name);
		times := count;
		while times > 0 do
		begin
			node := node.NextElement();
			times--;
		end
		return node;
	End;

	Function getNodeNumFmts(rootNode, id);
	Begin
		if not ifObj(rootNode) then return nil;
		node := rootNode.FirstChildElement('numFmt');
		num_id := inttostr(id);
		while ifObj(node) do
		begin
			if num_id = node.GetAttribute('numFmtId') then return node;
			node := node.NextElement();
		end
		return nil;
	End;

	Function copyNodeNumFmts(root, xf_node, id, obj);
	Begin
		if id = 0 then
		begin
			if ifnil(obj.FormatCode) then xf_node.SetAttribute('numFmtId', 0);
			else begin
				processNumFmtId(root, 'numFmts', obj);
				insertNode(root, 'numFmts', obj);
				xf_node.SetAttribute('numFmtId', obj.NumFmtId);
			end
		end
		else begin
			nodeName_node := root.FirstChildElement('numFmts');
			num_node := getNodeNumFmts(nodeName_node, id);
			processNumFmtId(root, 'numFmts', obj);
			new_node := nodeName_node.InsertEndChild(num_node.Marshal()[0]);
			count := strtoint(nodeName_node.GetAttribute('count'));
			nodeName_node.SetAttribute('count', count + 1);
			xf_node.SetAttribute('numFmtId', obj.NumFmtId);
			marshal := obj.Marshal();
			class(TSXml).UpdateNode(new_node, marshal['attributes'], marshal['children']);
		end
	End;

	Function copyNode(root, xf_node, nodeName, name, idName, id, obj);
	Begin
		if nodeName = 'numFmts' then return copyNodeNumFmts(root, xf_node, id, obj);
		nodeName_node := root.FirstChildElement(nodeName);
		if not ifObj(nodeName_node) then return;
		node := getNode(nodeName_node, name, id);
		new_node := nodeName_node.InsertEndChild(node.Marshal()[0]);
		count := strtoint(nodeName_node.GetAttribute('count'));
		nodeName_node.SetAttribute('count', count + 1);
		xf_node.SetAttribute(idName, count);

		if ifObj(obj) then
		begin
			marshal := obj.Marshal();
			class(TSXml).UpdateNode(new_node, marshal['attributes'], marshal['children']);
		end;
	End;

	Function insertNode(rootNode, childName, obj);
	Begin
		marshal := obj.Marshal();
		if not istable(marshal['children']) and not istable(marshal['attributes']) then return '0';
		node := rootNode.FirstChildElement(childName);
		if not ifObj(node) then
		begin
			info := array('name': childName, 'type': 'element', 'attributes': ('count': '0'));
			rootNode.InsertFirstChild(info);
			node := rootNode.FirstChildElement(childName);
		end
		count := node.GetAttribute('count');
		node.InsertEndChild(marshal);
		node.SetAttribute('count', strtoint(count) + 1);
		return count;
	End

	Function processNumFmtId(rootNode, childName, obj);
	Begin
		if ifnil(obj.FormatCode) then return;
		node := rootNode.FirstChildElement(childName);
		if not ifObj(node) then id := 176;
		else begin
			node := node.LastChildElement('numFmt');
			id := strtoint(node.GetAttribute('numFmtId')) + 1;
		end
		obj.numFmtId := id;
	End

private
	sheet_; //XmlSheet对象
	file_;  //TSExcelFile对象
	styleXmlFile_; //xmlFile对象
End;
