function write_style_css_directory($styleid, $parentlist, $dir = 'ltr')
{
	global $vbulletin;

	//verify that we have or can create a style directory
	$styledir = 'clientscript/vbulletin_css/style' . str_pad($styleid, 5, '0', STR_PAD_LEFT) . ($dir == 'ltr' ? 'l' : 'r');

	//if we have a file that's not a directory or not writable something is wrong.
	if (file_exists($styledir) AND (!is_dir($styledir) OR !is_writable($styledir)))
	{
		return false;
	}

	//clear any old files.
	if (file_exists($styledir))
	{
		delete_style_css_directory($styleid, $dir);
	}

	//create the directory -- if it still exists try to continue with the existing dir
	if (!file_exists($styledir))
	{
		if (!mkdir($styledir))
		{
			return false;
		}
	}

	//check for success.
	if (!is_dir($styledir) OR !is_writable($styledir))
	{
		return false;
	}

	//write out the files for this style.
	$set = $vbulletin->db->query_read($sql = "
		SELECT DISTINCT title
		FROM " . TABLE_PREFIX . "template
		WHERE styleid IN (" . $parentlist . ") AND title LIKE '%.css'
	");

	//collapse the list.
	$css_templates = array();
	while($row = $vbulletin->db->fetch_array($set))
	{
		$css_templates[] = $row['title'];
	}

	switch_css_style($styleid, $css_templates);

	if ($dir == 'ltr')
	{
		vB_Template_Runtime::addStyleVar('left', 'left');
		vB_Template_Runtime::addStyleVar('right', 'right');
		vB_Template_Runtime::addStyleVar('textdirection', 'ltr');
	}
	else
	{
		vB_Template_Runtime::addStyleVar('left', 'right');
		vB_Template_Runtime::addStyleVar('right', 'left');
		vB_Template_Runtime::addStyleVar('textdirection', 'rtl');
	}

	$templates = array();
	foreach ($css_templates AS $title)
	{
		//I'd call this a hack but there probably isn't a cleaner way to do this.
		//The css is published to a different directory than the css.php file
		//which means that relative urls that works for css.php won't work for the
		//published directory.  Unfortunately urls from the webroot don't work
		//because the forum often isn't located at the webroot and we can only
		//specify urls from the forum root.  And css doens't provide any way
		//of setting a base url like html does.  So we are left to "fixing"
		//any relative urls in the published css.
		//
		//We leave alone any urls starting with '/', 'http', and 'https:'
		//there are other valid urls, but nothing that people should be
		//using in our css files.

		$text = vB_Template::create($title)->render(true);
		$re = '#url\(\s*["\']?(?!/|http:|https:)#';
		$base = $vbulletin->options['bburl'];
		if ($base[-1] != '/')
		{
			$base .= '/';
		}
		$text = preg_replace ($re, "$0$base", $text);

		$templates[$title] = $text;
		if (!write_css_file("$styledir/$title", $text))
		{
			return false;
		}
	}

	static $vbdefaultcss, $cssfiles, $csstemplates;

	if (empty($vbdefaultcss))
	{
		$vbdefaultcss = array();

		// Now write the rollup templates
		require_once(DIR . '/includes/class_xml.php');
		$cssfiles = array();
		if ($handle = @opendir(DIR . '/includes/xml/'))
		{
			while (($file = readdir($handle)) !== false)
			{
				if (!preg_match('#^cssrollup_(.*).xml$#i', $file, $matches))
				{
					continue;
				}
				$css_key = preg_replace('#[^a-z0-9]#i', '', $matches[1]);
				$cssfiles["$css_key"]['name'] = $file;
			}
			closedir($handle);
		}

		if (empty($cssfiles['vbulletin']))	// opendir failed or cpnav_vbulletin.xml is missing
		{
			if (is_readable(DIR . '/includes/xml/cssrollup_vbulletin.xml'))
			{
				$cssfiles['vbulletin']['name'] = 'cssrollup_vbulletin.xml';
			}
			else
			{
				echo construct_phrase($vbphrase['could_not_open_x'], DIR . '/includes/xml/cssrollup_vbulletin.xml');
				exit;
			}
		}

		unset($cssfiles['vbulletin']);

		$xmlobj = new vB_XML_Parser(false, DIR . "/includes/xml/cssrollup_vbulletin.xml");
		$data = $xmlobj->parse();

		if (!is_array($data['rollup'][0]))
		{
			$data['rollup'] = array($data['rollup']);
		}

		foreach ($data['rollup'] AS $file)
		{
			foreach ($file['template'] AS $name)
			{
				$vbdefaultcss["$file[name]"] = $file['template'];
			}
		}

		foreach ($cssfiles AS $css_file => $file)
		{
			$xmlobj = new vB_XML_Parser(false, DIR . "/includes/xml/$file[name]");
			$data = $xmlobj->parse();

			if ($data['product'] AND empty($vbulletin->products["$data[product]"]))
			{
				// attached to a specific product and that product isn't enabled
				continue;
			}

			if (!is_array($data['rollup'][0]))
			{
				$data['rollup'] = array($data['rollup']);
			}

			$cssfiles["$css_file"]['css'] = $data['rollup'];
		}
	}

	foreach ($cssfiles AS $css_file => $files)
	{
		if (is_array($files['css']))
		{
			foreach ($files['css'] AS $file)
			{
				if (process_css_rollup_file($file['name'], $file['template'], $templates, $styledir, $vbdefaultcss) === false)
				{
					return false;
				}
			}
		}
	}

	foreach ($vbdefaultcss AS $xmlfile => $files)
	{
		if (process_css_rollup_file($xmlfile, $files, $templates, $styledir) === false)
		{
			return false;
		}
	}

	return true;
}
/**
 *	Writes style css directory on disk
 *
 *	@param int $styleid
 *	@param string $parentlist -- csv list of ancestors for this style
 *	@param string $dir -- the "direction" of the css to write.  Either 'ltr' or 'rtl' (there are actually two directories per style)
 */
function write_style_css_directory($styleid, $parentlist, $dir = 'ltr')
{
    //verify that we have or can create a style directory
    $styledir = DIR . vB_Api::instanceInternal('style')->fetchCssLocation() . '/style' . str_pad($styleid, 5, '0', STR_PAD_LEFT) . ($dir == 'ltr' ? 'l' : 'r');
    //if we have a file that's not a directory or not writable something is wrong.
    if (file_exists($styledir) and (!is_dir($styledir) or !is_writable($styledir))) {
        return false;
    }
    //clear any old files.
    if (file_exists($styledir)) {
        delete_style_css_directory($styleid, $dir, true);
    }
    //create the directory -- if it still exists try to continue with the existing dir
    if (!file_exists($styledir)) {
        if (!@mkdir($styledir)) {
            return false;
        }
    }
    //check for success.
    if (!is_dir($styledir) or !is_writable($styledir)) {
        return false;
    }
    //write out the files for this style.
    $parentlistarr = explode(',', $parentlist);
    $set = vB::getDbAssertor()->assertQuery('vBForum:fetchParentTemplates', array('parentlist' => $parentlistarr));
    //collapse the list.
    $css_templates = array();
    foreach ($set as $row) {
        $css_templates[] = $row['title'];
    }
    $stylelib = vB_Library::instance('Style');
    $stylelib->switchCssStyle($styleid, $css_templates);
    if ($dir == 'ltr') {
        vB_Template_Runtime::addStyleVar('left', 'left');
        vB_Template_Runtime::addStyleVar('right', 'right');
        vB_Template_Runtime::addStyleVar('textdirection', 'ltr');
    } else {
        vB_Template_Runtime::addStyleVar('left', 'right');
        vB_Template_Runtime::addStyleVar('right', 'left');
        vB_Template_Runtime::addStyleVar('textdirection', 'rtl');
    }
    // Get new css cache bust
    $stylelib->setCssFileDate($styleid);
    $cssfiledate = $stylelib->getCssFileDate($styleid);
    $base = get_base_url_for_css();
    if ($base === false) {
        return false;
    }
    $templates = array();
    foreach ($css_templates as $title) {
        //I'd call this a hack but there probably isn't a cleaner way to do this.
        //The css is published to a different directory than the css.php file
        //which means that relative urls that works for css.php won't work for the
        //published directory.  Unfortunately urls from the webroot don't work
        //because the forum often isn't located at the webroot and we can only
        //specify urls from the forum root.  And css doens't provide any way
        //of setting a base url like html does.  So we are left to "fixing"
        //any relative urls in the published css.
        //
        //We leave alone any urls starting with '/', 'http', and 'https:'
        //there are other valid urls, but nothing that people should be
        //using in our css files.
        $text = vB_Template::create($title)->render(true);
        //update image urls to be fully qualified.
        $re = '#url\\(\\s*["\']?(?!/|http:|https:|"/|\'/)#';
        $text = preg_replace($re, "\$0{$base}", $text);
        $text = vB_String::getCssMinifiedText($text);
        $templates[$title] = $text;
        if (!write_css_file("{$styledir}/{$cssfiledate}-{$title}", $text)) {
            return false;
        }
    }
    static $vbdefaultcss = array(), $cssfiles = array();
    if (empty($vbdefaultcss)) {
        require_once DIR . '/includes/class_xml.php';
        $cssfilelist = vB_Api_Product::loadProductXmlList('cssrollup', true);
        if (empty($cssfilelist['vbulletin'])) {
            $vbphrase = vB_Api::instanceInternal('phrase')->fetch(array('could_not_open_x'));
            echo construct_phrase($vbphrase['could_not_open_x'], DIR . '/includes/xml/cssrollup_vbulletin.xml');
            exit;
        } else {
            $mainfile = array_shift($cssfilelist);
        }
        $xmlobj = new vB_XML_Parser(false, $mainfile);
        $data = $xmlobj->parse();
        if (!is_array($data['rollup'][0])) {
            $data['rollup'] = array($data['rollup']);
        }
        foreach ($data['rollup'] as $file) {
            foreach ($file['template'] as $name) {
                $vbdefaultcss["{$file['name']}"] = $file['template'];
            }
        }
        foreach ($cssfilelist as $css_file => $file) {
            $xmlobj = new vB_XML_Parser(false, $file);
            $data = $xmlobj->parse();
            $products = vB::getDatastore()->getValue('products');
            if ($data['product'] and empty($products["{$data['product']}"])) {
                // attached to a specific product and that product isn't enabled
                continue;
            }
            if (!is_array($data['rollup'][0])) {
                $data['rollup'] = array($data['rollup']);
            }
            $cssfiles[$css_file]['css'] = $data['rollup'];
        }
    }
    foreach ($cssfiles as $css_file => $files) {
        if (is_array($files['css'])) {
            foreach ($files['css'] as $file) {
                if (process_css_rollup_file($file['name'], $file['template'], $templates, $styleid, $styledir, $vbdefaultcss) === false) {
                    return false;
                }
            }
        }
    }
    foreach ($vbdefaultcss as $xmlfile => $files) {
        if (process_css_rollup_file($xmlfile, $files, $templates, $styleid, $styledir) === false) {
            return false;
        }
    }
    return true;
}